Creating an exploratory plot array In this exercise, you’ll construct a simple exploratory plot from a data frame that gives values for three variables, recorded over two winter heating seasons. The variables are:

Temp: a measure of the outside temperature during one week Gas: the amount of heating gas consumed during that week Insul: a categorical variable with two values, indicating whether the measurements were made before or after an insulation upgrade was made to the house

# Load MASS package
library(MASS)

Attaching package: 'MASS'

The following object is masked from 'package:dplyr':

    select
# Plot whiteside data
plot(whiteside)

Creating an explanatory scatterplot In constrast to the exploratory analysis plot you created in the previous exercise, this exercise asks you to create a simple explanatory scatterplot, suitable for sharing with others.

Here, it is important to make editorial choices in constructing this plot, rather than depending entirely on default options. In particular, the important editorial aspects of this plot are: first, the variables to be plotted, and second, the axis labels, which are specified as strings to the xlab and ylab arguments to the plot() function.

# Plot Gas vs. Temp
plot(whiteside$Temp, whiteside$Gas,
    xlab = "Outside temperature", ylab = "Heating gas consumption")

The plot() function is generic One of the key features of the plot() function is that it is generic, meaning that the results of applying the function depend on the nature of the object to which it is applied.

In the first exercise of this chapter, applying the plot() function to the whiteside data frame resulted in a plot array. Here, we obtain a fundamentally different kind of result when we apply the same function to Insul, a factor variable from the same data frame.

# Apply the plot() function to Insul
plot(whiteside$Insul)

Adding details to a plot using point shapes, color, and reference lines Adding additional details to your explanatory plots can help emphasize certain aspects of your data. For example, by specifying the pch and col arguments to the plot() function, you can add different point shapes and colors to show how different variables or subsets of your data relate to each other. In addition, you can add a new set of points to your existing scatterplot with the points() function, and add reference lines with the abline() function.

This exercise asks you to use these methods to create an enhanced scatterplot that effectively shows how three variables in the Cars93 data frame relate to each other. These variables are:

Price: the average sale price for a car Max.Price: the highest recorded price for that car Min.Price: the lowest recorded price for that car

# Load the MASS package
library(MASS)
# Plot Max.Price vs. Price as red triangles
plot(Cars93$Price,Cars93$Max.Price, pch = 17, col = "red")
# Add Min.Price vs. Price as blue circles
points( Cars93$Price,Cars93$Min.Price, pch = 16, col = "blue")
# Add an equality reference line with abline()
abline(a = 0, b = 1, lty = 2)

Creating multiple plot arrays You can plot multiple graphs on a single pane using the par() function with its mfrow parameter. For example, par(mfrow = c(1, 2)) creates a plot array with 1 row and 2 columns, allowing you to view two graphs side-by-side. This way, you can compare and contrast different datasets or different views of the same dataset. This exercise asks you to compare two views of the Animals2 dataset from the robustbase package, differing in how its variables are represented.

The objective of this exercise is to emphasize that the original representation of the variables that we have in a dataset is not always the best one for visualization or analysis. By representing the original variables in log scale, for example, we can better see and understand the data.

# Load the robustbase package
library(robustbase)
# Set up the side-by-side plot array
par(mfrow = c(1,2))
# First plot: brain vs. body in its original form
plot(Animals2$body, Animals2$brain)
# Add the first title
title("Original representation")
# Second plot: log-log plot of brain vs. body
plot(Animals2$body, Animals2$brain, log="xy")
# Add the second title
title("Log-log plot")

Avoid pie charts The same dataset can be displayed or summarized in many different ways, but some are much more suitable than others.

Despite their general popularity, pie charts are often a poor choice. Though R allows pie charts with the pie() function, even the help file for this function argues against their use. Specifically, the help file includes a “Note” that begins with the words: “Pie charts are a very bad way of displaying information.”

Bar charts are a recommended alternative and, in this exercise, you’ll see why.

# Load the insuranceData package
library(insuranceData)
# Use the data() function to get the dataCar data frame
data(dataCar)
# Set up a side-by-side plot array
par(mfrow = c(1, 2))
# Create a table of veh_body record counts and sort
tbl <- sort(table(dataCar$veh_body),
            decreasing = TRUE)
# Create the pie chart and give it a title
pie(tbl)
title("Pie chart")
# Create the barplot with perpendicular, half-sized labels
barplot(tbl, las = 2, cex.names = 0.5)
# Add a title
title("Bar chart")

The hist() and truehist() functions Histograms are probably the best-known way of looking at how the values of a numerical variable are distributed over their range, and R provides several different histogram implementations.

The purpose of this exercise is to introduce two of these:

hist() is part of base R and its default option yields a histogram based on the number of times a record falls into each of the bins on which the histogram is based. truehist() is from the MASS package and scales these counts to give an estimate of the probability density.

# Set up a side-by-side plot array
par(mfrow = c(1,2))
# Create a histogram of counts with hist()
hist(Cars93$Horsepower, main = "hist() plot")
# Create a normalized histogram with truehist()
truehist(Cars93$Horsepower, main = "truehist() plot") 

Density plots as smoothed histograms While they are probably not as well known as the histogram, density estimates may be regarded as smoothed histograms, designed to give a better estimate of the density function for a random variable.

In this exercise, you’ll use the ChickWeight dataset, which contains a collection of chicks’ weights. You will first select for the chicks that are 16 weeks old. Then, you’ll create a histogram using the truehist() function, and add its density plot on top, using the lines() and density() functions with their default options. The density plot of this type of variable is often expected to conform approximately to the bell-shaped curve, otherwise known as the Gaussian distribution. Let’s find out whether that’s the case for this dataset.

# Create index16, pointing to 16-week chicks
index16 <- which(ChickWeight$Time==16)
# Get the 16-week chick weights
weights = ChickWeight$weight[index16]
# Plot the normalized histogram
truehist(weights)
# Add the density curve to the histogram
lines(density(weights)) 

Using the qqPlot() function to see many details in data A practical limitation of both histograms and density estimates is that, if we want to know whether the Gaussian distribution assumption is reasonable for our data, it is difficult to tell.

The quantile-quantile plot, or QQ-plot, is a useful alternative: we sort our data, plot it against a specially-designed x-axis based on our reference distribution (e.g., the Gaussian “bell curve”), and look to see whether the points lie approximately on a straight line. In R, several QQ-plot implementations are available, but the most convenient one is the qqPlot() function in the car package.

The first part of this exercise applies this function to the 16-week chick weight data considered in the last exercise, to show that the Gaussian distribution appears to be reasonable here. The second part of the exercise applies this function to another variable where the Gaussian distribution is obviously a poor fit, but the results also show the presence of repeated values (flat stretches in the plot) and portions of the data range where there are no observations (vertical “jumps” in the plot).

# Load the car package to make qqPlot() available
library(car)

Attaching package: 'car'

The following object is masked from 'package:Lahman':

    Salaries

The following object is masked from 'package:purrr':

    some

The following object is masked from 'package:dplyr':

    recode
# Create index16, pointing to 16-week chicks
index16 <- which(ChickWeight$Time == 16)
# Get the 16-week chick weights
weights <- ChickWeight$weight[index16]
# Show the normal QQ-plot of the chick weights
qqPlot(weights)

# Show the normal QQ-plot of the Boston$tax data
qqPlot(Boston$tax)

The sunflowerplot() function for repeated numerical data A scatterplot represents each (x, y) pair in a dataset by a single point. If some of these pairs are repeated (i.e. if the same combination of x and y values appears more than once and thus lie on top of each other), we can’t see this in a scatterplot. Several approaches have been developed to deal with this problem, including jittering, which adds small random values to each x and y value, so repeated points will appear as clusters of nearby points.

A useful alternative that is equally effective in representing repeated data points is the sunflowerplot, which represents each repeated point by a “sunflower,” with one “petal” for each repetition of a data point.

This exercise asks you to construct both a scatterplot and a sunflowerplot from the same dataset, one that contains repeated data points. Comparing these plots allows you to see how much information can be lost in a standard scatterplot when some data points appear many times.

# Set up a side-by-side plot array
par(mfrow = c(1,2))
# Create the standard scatterplot
plot( Boston$zn,Boston$rad)
# Add the title
title("Standard scatterplot")
# Create the sunflowerplot
sunflowerplot(Boston$zn, Boston$rad)
# Add the title
title("Sunflower plot")

Useful options for the boxplot() function The boxplot() function shows how the distribution of a numerical variable y differs across the unique levels of a second variable, x. To be effective, this second variable should not have too many unique levels (e.g., 10 or fewer is good; many more than this makes the plot difficult to interpret).

The boxplot() function also has a number of optional parameters and this exercise asks you to use three of them to obtain a more informative plot:

varwidth allows for variable-width boxplots that show the different sizes of the data subsets. log allows for log-transformed y-values. las allows for more readable axis labels. This exercise also illustrates the use of the formula interface: y ~ x indicates that we want a boxplot of the y variable across the different levels of the x variable. See ?boxplot for more details.

# Create a variable-width boxplot with log y-axis & horizontal labels
boxplot(crim~rad, data=Boston, varwidth=TRUE , log = "y", las =1)
# Add a title
title("Crime rate vs. radial highway index")

Using the mosaicplot() function A mosaic plot may be viewed as a scatterplot between categorical variables and it is supported in R with the mosaicplot() function.

As this example shows, in addition to categorical variables, this plot can also be useful in understanding the relationship between numerical variables, either integer- or real-valued, that take only a few distinct values.

More specifically, this exercise asks you to construct a mosaic plot showing the relationship between the numerical carb and cyl variables from the mtcars data frame, variables that exhibit 6 and 3 unique values, respectively.

# Create a mosaic plot using the formula interface
mosaicplot(carb~cyl, data = mtcars) 

Using the bagplot() function A single box plot gives a graphical representation of the range of variation in a numerical variable, based on five numbers:

The minimum and maximum values The median (or “middle”) value Two intermediate values called the lower and upper quartiles In addition, the standard box plot computes a nominal data range from three of these numbers and flags points falling outside this range as outliers, representing them as distinct points.

The bag plot extends this representation to two numerical variables, showing their relationship, both within two-dimensional “bags” corresponding to the “box” in the standard boxplot, and indicating outlying points outside these limits.

This exercise asks you to construct, first, side-by-side box plots of the Min.Price and Max.Price variables from the mtcars dataset, and then to use the bagplot() function from the aplpack package to construct the corresponding bag plot.

# Create a side-by-side boxplot summary
par(mfrow = c(1,2))
boxplot(Cars93$Min.Price, Cars93$Max.Price)
# Load aplpack to make the bagplot() function available
library(aplpack)
Loading required package: tcltk
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun
running command ''/usr/bin/otool' -L '/Library/Frameworks/R.framework/Resources/library/tcltk/libs//tcltk.so'' had status 1
# Create a bagplot for the same two variables
bagplot(Cars93$Min.Price, Cars93$Max.Price , cex = 1.2)
# Add an equality reference line
abline(0,1,lty = 2)

Plotting correlation matrices with the corrplot() function Correlation matrices were introduced in the video as a useful tool for obtaining a preliminary view of the relationships between multiple numerical variables.

This exercise asks you to use the corrplot() function from the corrplot package to visualize this correlation matrix for the numerical variables from the UScereal data frame in the MASS package. Recall that in this version of these plots, ellipses that are thin and elongated indicate a large correlation value between the indicated variables, while ellipses that are nearly circular indicate correlations near zero.

# Load the corrplot library for the corrplot() function
library(corrplot)
corrplot 0.84 loaded
# Extract the numerical variables from UScereal
numericalVars = UScereal[2:10]
# Compute the correlation matrix for these variables
corrMat <- cor(numericalVars)
# Generate the correlation ellipse plot
corrplot(corrMat, method = "ellipse")

Building and plotting rpart() models It was noted in the video that decision trees represent a popular form of predictive model because they are easy to visualize and explain. It was also noted that the rpart package is probably the most popular of several R packages that can be used to build and visualize these models.

This exercise asks you to, first, build a decision tree model using the rpart() function from this package, and then display the resulting model structure using the generic functions plot() and text().

# Load the rpart library
library(rpart)
# Fit an rpart model to predict medv from all other Boston variables
tree_model <- rpart(medv~., data = Boston)
# Plot the structure of this decision tree model
plot(tree_model)
# Add labels to this plot
text(tree_model, cex = 0.7)

Introduction to the par() function You already saw how the mfrow parameter to the par() function could be used to plot multiple graphs in one pane. The par() function also allows you to set many other graphics parameters, whose values will remain in effect until they are reset by a subsequent par() call.

Specifically, a call to the par() function with no parameters specified will return a list whose element names each specify a graphics parameter and whose element values specify the corresponding default values of these parameters. These parameters may be set by a call in the form par(name = value) where name is the name of the parameter to be set and value is the value to be assigned to this parameter.

The purpose of this exercise is to give an idea of what these graphics parameters are. In the subsequent exercises we’ll show how some of these parameters can be used to enhance plot results.

# Assign the return value from the par() function to plot_pars
plot_pars <- par()
# Display the names of the par() function's list elements
names(plot_pars)
 [1] "xlog"      "ylog"      "adj"       "ann"       "ask"       "bg"        "bty"       "cex"       "cex.axis" 
[10] "cex.lab"   "cex.main"  "cex.sub"   "cin"       "col"       "col.axis"  "col.lab"   "col.main"  "col.sub"  
[19] "cra"       "crt"       "csi"       "cxy"       "din"       "err"       "family"    "fg"        "fig"      
[28] "fin"       "font"      "font.axis" "font.lab"  "font.main" "font.sub"  "lab"       "las"       "lend"     
[37] "lheight"   "ljoin"     "lmitre"    "lty"       "lwd"       "mai"       "mar"       "mex"       "mfcol"    
[46] "mfg"       "mfrow"     "mgp"       "mkh"       "new"       "oma"       "omd"       "omi"       "page"     
[55] "pch"       "pin"       "plt"       "ps"        "pty"       "smo"       "srt"       "tck"       "tcl"      
[64] "usr"       "xaxp"      "xaxs"      "xaxt"      "xpd"       "yaxp"      "yaxs"      "yaxt"      "ylbias"   
# Display the number of par() function list elements
length(plot_pars)
[1] 72

Exploring the type option One of the important graphics parameters that can be set with the par() function is mfrow, which specifies the numbers of rows and columns in an array of plots. Valid values for this parameter are two-element numerical vectors, whose first element specifies the number of rows in the plot array and the second element specifies the number of rows.

A more detailed discussion of using the mfrow parameter is given in Chapter 4 of this course. For now, note that to specify a plot array with three rows and one column, the command would be par(mfrow = c(3, 1)).

The following exercise also introduces the type parameter for the plot() command, which specifies how the plot is drawn. The specific type values used here are:

“p” for “points” “l” for “lines” “o” for “overlaid” (i.e., lines overlaid with points) “s” for “steps”

# Set up a 2-by-2 plot array
par(mfrow = c(2,2))
# Plot the Animals2 brain weight data as points
plot(Animals2$brain, type = "p")
# Add the title
title("points")
# Plot the brain weights with lines
plot(Animals2$brain, type = "l")
# Add the title
title("lines")
# Plot the brain weights as lines overlaid with points
plot(Animals2$brain, type = "o")
# Add the title
title("overlaid")
# Plot the brain weights as steps
plot(Animals2$brain, type = "s")
# Add the title
title("steps")

The surprising utility of the type “n” option The type = “n” option was discussed in the video and this exercise provides a simple example. This option is especially useful is when we are plotting data from multiple sources on a common set of axes. In such cases, we can compute ranges for the x- and y-axes so that all data points will appear on the plot, and then add the data with subsequent calls to points() or lines() as appropriate.

This exercise asks you to generate a plot that compares mileage vs. horsepower data from two different sources: the mtcars data frame in the datasets package and the Cars93 data frame in the MASS package. To distinguish the different results from these data sources, the graphics parameter pch is used to specify point shapes. See ?points for a comprehensive list of some pch values and their corresponding point shapes.

# Compute max_hp
max_hp <- max(Cars93$Horsepower, mtcars$hp)
# Compute max_mpg
max_mpg <- max(Cars93$MPG.city, Cars93$MPG.highway,
               mtcars$mpg)
# Create plot with type = "n"               
plot(Cars93$Horsepower, Cars93$MPG.city,
     type = "n", xlim = c(0, max_hp),
     ylim = c(0, max_mpg), xlab = "Horsepower",
     ylab = "Miles per gallon")
# Add open circles to plot
points(mtcars$hp, mtcars$mpg, pch = 1)
# Add solid squares to plot
points(Cars93$Horsepower, Cars93$MPG.city,
       pch = 15)
# Add open triangles to plot
points(Cars93$Horsepower, Cars93$MPG.highway,
       pch = 2)

The lines() function and line types As noted in Chapter 2, numerical data is often assumed to conform approximately to a Gaussian probability distribution, characterized by the bell curve. One point of this exercise is to show what this bell curve looks like for exactly Gaussian data and the other is to show how the lines() function can be used to add lines to an existing plot.

The curves you are asked to draw here have the same basic shape but differ in their details (specifically, the means and standard deviations of these Gaussian distributions are different). For this reason, it is useful to draw these curves with different line types to help us distinguish them.

Note that line types are set by the lty argument, with the default value lty = 1 specifying solid lines, lty = 2 specifying dashed lines, and lty = 3 specifying dotted lines. Also note that the lwd argument specifies the relative width.

# Create the numerical vector x
x <- seq(0, 10, length = 200)
# Compute the Gaussian density for x with mean 2 and standard deviation 0.2
gauss1 <- dnorm(x, mean = 2, sd = 0.2)
# Compute the Gaussian density with mean 4 and standard deviation 0.5
gauss2 <- dnorm(x, mean = 4, sd = 0.5)
# Plot the first Gaussian density
plot(x, gauss1, type = "l", ylab = "Gaussian probability density")
# Add lines for the second Gaussian density
lines(x, gauss2, lty = 2, lwd = 3)

The points() function and point types One advantage of specifying the pch argument locally is that, in a call to functions like plot() or points(), local specification allows us to make pch depend on a variable in our dataset. This provides a simple way of indicating different data subsets with different point shapes or symbols.

This exercise asks you to generate two plots of mpg vs. hp from the mtcars data frame in the datasets package. The first plot specifies the point shapes using numerical values of the pch argument defined by the cyl variable in the mtcars data frame. The second plot illustrates the fact that pch can also be specified as a vector of single characters, causing each point to be drawn as the corresponding character.

# Create an empty plot using type = "n"
plot(mtcars$hp,mtcars$mpg,  type = "n", xlab = "Horsepower", ylab = "Gas mileage")
# Add points with shapes determined by cylinder number
points(mtcars$hp,mtcars$mpg,  pch = as.numeric(mtcars$cyl))

# Create a second empty plot
plot(mtcars$hp,mtcars$mpg,  type = "n", xlab = "Horsepower", ylab = "Gas mileage")
# Add points with shapes as cylinder characters
points(mtcars$hp, mtcars$mpg,  pch = as.character(mtcars$cyl))

Adding trend lines from linear regression models The low-level plot function abline() adds a straight line to an existing plot. This line is specified by an intercept parameter a and a slope parameter b, and the simplest way to set these parameters is directly. For example, the command abline(a = 0, b = 1) adds an equality reference line with zero intercept and unit (i.e. 1) slope: points for which y = x fall on this reference line, while points with y > x fall above it, and points with y < x fall below it.

An alternative way of specifying these parameters is through a linear regression model that determines them from data. One common application is to generate a scatterplot of y versus x, then fit a linear model that predicts y from x, and finally call abline() to add this best fit line to the plot.

This exercise asks you to do this for the Gas versus Temp data from the whiteside data frame in the MASS package. The standard R function that fits linear regression models is lm(), which supports the formula interface. Thus, to fit a linear model that predicts y from x in the data frame df, the call would be lm(y ~ x, data = df). This call returns a linear model object, which can then be passed as an argument to the abline() function to draw the desired line on our plot.

# Build a linear regression model for the whiteside data
linear_model <- lm(Gas~Temp, data = whiteside)
# Create a Gas vs. Temp scatterplot from the whiteside data
plot(whiteside$Temp, whiteside$Gas)
# Use abline() to add the linear regression line
abline(linear_model, lty =2)

Using the text() function to label plot features One of the main uses of the text() function is to add informative labels to a data plot. The text() function takes three arguments:

x, which specifies the value for the x variable, y, which specifies the value for the y variable, and label, which specifies the label for the x-y value pair. This exercise asks you to first create a scatterplot of city gas mileage versus horsepower from the Cars93 data, then identify an interesting subset of the data (i.e. the 3-cylinder cars) and label these points. You will find that assigning a vector to the x, y, and label arguments to text() will result in labeling multiple points at once.

# Create MPG.city vs. Horsepower plot with solid squares
plot(Cars93$Horsepower, Cars93$MPG.city, pch = 15)
# Create index3, pointing to 3-cylinder cars
index3 <- which(Cars93$Cylinders ==3)
# Add text giving names of cars next to data points
text(x = Cars93$Horsepower[index3], 
     y = Cars93$MPG.city[index3],
     labels = Cars93$Make[index3],
     adj = 0)

Adjusting text position, size, and font The previous exercise added explanatory text to a scatterplot. The purpose of this exercise is to improve this plot by modifying the text placement, increasing the text size, and displaying the text in boldface.

It was noted that the adj argument to the text() function determines the horizontal placement of the text and it can take any value between 0 and 1. In fact, this argument can take values outside this range. That is, making this value negative causes the text to start to the right of the specified x position. Similarly, making adj greater than 1 causes the text to end to the left of the x position.

Another useful optional argument for the text() function is cex, which scales the default text size. As a specific example, setting cex = 1.5 increases the text size by 50 percent, relative to the default value. Similarly, specifying cex = 0.8 reduces the text size by 20 percent.

Finally, the third optional parameter used here is font, which can be used to specify one of four text fonts: font = 1 is the default text font (neither italic nor bold), font = 2 specifies bold face text, font = 3 specifies italic text, and font = 4 specifies both bold and italic text.

# Plot MPG.city vs. Horsepower as open circles
plot(Cars93$Horsepower, Cars93$MPG.city, pch = 1)
# Create index3, pointing to 3-cylinder cars
index3 <- which(Cars93$Cylinders == 3)
# Highlight 3-cylinder cars as solid circles
points(Cars93$Horsepower[index3],
       Cars93$MPG.city[index3],
       pch = 16)
# Add car names, offset from points, with larger bold text
text(Cars93$Horsepower[index3],
     Cars93$MPG.city[index3],
     Cars93$Make[index3],
     adj = -0.2, cex = 1.2, font = 4)

Rotating text with the srt argument In addition to the optional arguments used in the previous exercises, the text() function also supports a number of other optional arguments that can be used to enhance the text. This exercise uses the cex argument to reduce the text size and introduces two new arguments. The first is the col argument that specifies the color used to display the text, and the second is the srt argument that allows us to rotate the text.

Color has been used in several of the previous exercises to specify point colors, and the effective use of color is discussed further in Chapter 5. One of the points of this exercise is to show that the specification of text color with the text() function is essentially the same as the specification of point color with the plot() function. As a specific example, setting col = “green” in the text() function causes the text to appear in green. If col is not specified, the text appears in the default color set by the par() function, which is typically black.

The srt parameter allows us to rotate the text through an angle specified in degrees. The typical default value (set by the par() function) is 0, causing the text to appear horizontally, reading from left to right. Specifying srt = 90 causes the text to be rotated 90 degrees counter-clockwise so that it reads from bottom to top instead of left to right.

# Plot Gas vs. Temp as solid triangles
plot(whiteside$Temp, whiteside$Gas, pch = 17)
# Create indexB, pointing to "Before" data
indexB <- which(whiteside$Insul == "Before")
# Create indexA, pointing to "After" data
indexA <- which(whiteside$Insul == "After")
# Add "Before" text in blue, rotated 30 degrees, 80% size
text(x = whiteside$Temp[indexB], y = whiteside$Gas[indexB],
     labels = "Before", col = "blue", srt = 30, cex = 0.8)
# Add "After" text in red, rotated -20 degrees, 80% size
text(x = whiteside$Temp[indexA], y = whiteside$Gas[indexA],
     labels = "After", col = "red", srt = -20, cex = 0.8)

Using the legend() function The video described and illustrated the use of the legend() function to add explanatory text to a plot.

This exercise asks you to first create a scatterplot and then use this function to add explanatory text for the point shapes that identify two different data subsets.

# Set up and label empty plot of Gas vs. Temp
plot(whiteside$Temp, whiteside$Gas,
     type = "n", xlab = "Outside temperature",
     ylab = "Heating gas consumption")
# Create indexB, pointing to "Before" data
indexB <- which(whiteside$Insul == "Before")
# Create indexA, pointing to "After" data
indexA <- which(whiteside$Insul == "After")
# Add "Before" data as solid triangles
points(whiteside$Temp[indexB], whiteside$Gas[indexB], pch=17)
# Add "After" data as open circles
points(whiteside$Temp[indexA], whiteside$Gas[indexA], pch=1)
# Add legend that identifies points as "Before" and "After"
legend("topright", pch = c(17,1), 
       legend = c("Before", "After"))

Adding custom axes with the axis() function Typical base graphics functions like boxplot() provide x- and y-axes by default, with a label for the x-axis below the plot and one for the y-axis label to the left of the plot. These labels are generated automatically from the variable names used to generate the plot. Sometimes, we want to provide our own axes labels, and R makes this possible in two steps: first, we suppress the default axes when we create the plot by specifying axes = FALSE; then, we call the low-level graphics function axis() to create the axes we want.

In this exercise, you’re asked to create your own labels using the axis() function with the side, at, and labels arguments. The side argument tells the function which axis to create: a value of 1 adds an axis below the plot; 2 adds an axis on the left; 3 puts it across the top; and 4 puts it on the right side. The second argument, at, is a vector that defines points where tick-marks will be drawn on the axis. The third argument, labels, is a vector that defines labels at each of these tick-marks.

One example of a boxplot with custom axes was presented in the video. This exercise asks you to create another example showing the relationship between the sugars variable and the shelf variable from the UScereal data frame in the MASS package.

# Create a boxplot of sugars by shelf value, without axes
boxplot(sugars ~ shelf, data = UScereal,
        axes = FALSE)
# Add a default y-axis to the left of the boxplot
axis(side = 2)
# Add an x-axis below the plot, labelled 1, 2, and 3
axis(side = 1, at = c(1, 2, 3))
# Add a second x-axis above the plot
axis(side = 3, at = c(1, 2, 3),
     labels = c("floor", "middle", "top"))

Using the supsmu() function to add smooth trend curves As we saw in the video, some scatterplots exhibit fairly obvious trends that are not linear. In such cases, we may want to add a curved trend line that highlights this behavior of the data and the supsmu() function represents one way of doing this.

To use this function, we need to specify values for the required arguments x and y, but it also has a number of optional arguments. Here, we consider the optional bass argument, which controls the degree of smoothness in the resulting trend curve. The default value is 0, but specifying larger values (up to a maximum of 10) results in a smoother curve. This exercise asks you to use the supsmu() function to add two trend lines to a scatterplot, one using the default parameters and the other with increased smoothness.

# Create a scatterplot of MPG.city vs. Horsepower
plot(Cars93$Horsepower, Cars93$MPG.city)
# Call supsmu() to generate a smooth trend curve, with default bass
trend1 <- supsmu(Cars93$Horsepower, Cars93$MPG.city)
# Add this trend curve to the plot
lines(trend1)
# Call supsmu() for a second trend curve, with bass = 10
trend2 <- supsmu(Cars93$Horsepower, Cars93$MPG.city, bass =10)
# Add this trend curve as a heavy, dotted line
lines(trend2, lty = 3, lwd = 2)

Too much is too much The first example presented in Chapter 1 applied the plot() function to a data frame, yielding an array of scatterplots with one for each pair of columns in the data frame. Thus, the number of plots in this array is equal to the square of the number of columns in the data frame.

This means that if we apply the plot() function to a data frame with many columns, we will generate an enormous array of scatterplots, each of which will be too small to be useful. The purpose of this exercise is to provide a memorable example.

# Compute the number of plots to be displayed
ncol(Cars93)^2
[1] 729
# Plot the array of scatterplots
plot(Cars93)
Error in plot.new() : figure margins too large

Deciding how many scatterplots is too many As noted in the video, the matplot() function can be used to easily generate a plot with several scatterplots on the same set of axes. By default, the points in these scatterplots are represented by the numbers 1 through n, where n is the total number of scatterplots included, but most of the options available with the plot() function are also possible by specifying the appropriate arguments.

This exercise asks you to set up a plot array with four of these multiple scatterplot displays, each including one more scatterplot than the previous one. The point of this exercise is to encourage you to judge for yourself how many scatterplots is too many?.

# Construct the vector keep_vars
keep_vars <- c("calories", "protein", "fat",
               "fibre", "carbo", "sugars")
# Use keep_vars to extract the desired subset of UScereal
df <- UScereal[, keep_vars]
# Set up a two-by-two plot array
par(mfrow = c(2,2))
# Use matplot() to generate an array of two scatterplots
matplot(UScereal$calories, UScereal[c("protein", "fat")], xlab = "calories",ylab = "")
# Add a title
title("Two scatterplots")
# Use matplot() to generate an array of three scatterplots
matplot(UScereal$calories, UScereal[c("protein", "fat", "fibre")], xlab = "calories",ylab = "")
# Add a title
title("Three scatterplots")
# Use matplot() to generate an array of four scatterplots
matplot(UScereal$calories, UScereal[c("protein", "fat", "fibre", "carbo")], xlab = "calories",ylab = "")
# Add a title
title("Four scatterplots")
# Use matplot() to generate an array of five scatterplots
matplot(UScereal$calories, UScereal[c("protein", "fat", "fibre", "carbo", "sugars")], xlab = "calories",ylab = "")
# Add a title
title("Five scatterplots")

How many words is too many? The main point of the previous two exercises has been to show that scatterplot arrays lose their utility if they are allowed to become too complex, either including too many plots, or attempting to include too many scatterplots on one set of axes. More generally, any data visualization loses its utility if it becomes too complex.

This exercise asks you to consider this problem with wordclouds, displays that present words in varying sizes depending on their frequency. That is, more frequent words appear larger in the display, while rarer words appear in a smaller font.

In R, wordclouds are easy to generate with the wordcloud() function in the wordcloud package. This function is called with a character vector of words, and a second numerical vector giving the number of times each word appears in the collection used to generate the wordcloud.

Two other useful arguments for this function are scale and min.freq. The scale argument is a two-component numerical vector giving the relative size of the largest word in the display and that of the smallest word. The wordcloud only includes those words that occur at least min.freq times in the collection and the default value for this argument is 3.

library(wordcloud)
Loading required package: RColorBrewer
# Create mfr_table of manufacturer frequencies
mfr_table <- table(Cars93$Manufacturer)
# Create the default wordcloud from this table
wordcloud(words = names(mfr_table), 
          freq = as.numeric(mfr_table), 
          scale = c(2, 0.25))

# Change the minimum word frequency
wordcloud(words = names(mfr_table), 
          freq = as.numeric(mfr_table), 
          scale = c(2, 0.25), 
          min.freq = 1)

# Create model_table of model frequencies
model_table <- table(Cars93$Model)
# Create the wordcloud of all model names with smaller scaling
wordcloud(words = names(model_table), 
          freq = as.numeric(model_table), 
          scale = c(0.75, 0.25), 
          min.freq = 1)

The Anscombe quartet This exercise and the next one are based on the Anscombe quartet, a collection of four datasets that appear to be essentially identical on the basis of simple summary statistics like means and standard deviations. For example, the mean x-values for these datasets are identical to three digits, while the mean y-values differ only in the third digit.

In spite of these apparent similarities, the behavior of the four datasets is quite different and this becomes immediately apparent when we plot them.

# Set up a two-by-two plot array
par(mfrow = c(2,2))
# Plot y1 vs. x1 
plot(anscombe$x1, anscombe$y1)
# Plot y2 vs. x2
plot(anscombe$x2, anscombe$y2)
# Plot y3 vs. x3
plot(anscombe$x3, anscombe$y3)
# Plot y4 vs. x4
plot(anscombe$x4, anscombe$y4)

The utility of common scaling and individual titles The plots you generated in the previous exercise showed that the four Anscombe quartet datasets have very different appearances, but a careful examination of these plots reveals that they exhibit different ranges of x and y values.

The point of this exercise is to illustrate how much more clearly we can see the differences in these datasets if we plot all of them with the same x and y ranges. This exercise also illustrates the utility of improving the x- and y-axis labels and of adding informative plot titles.

# Define common x and y limits for the four plots
xmin <- 4
xmax <- 19
ymin <- 3
ymax <- 13
# Set up a two-by-two plot array
par(mfrow = c(2,2))
# Plot y1 vs. x1 with common x and y limits, labels & title
plot(anscombe$x1, anscombe$y1,
     xlim = c(xmin, xmax),
     ylim = c(ymin, ymax),
     xlab = "x value", ylab = "y value",
     main = "First dataset")
# Do the same for the y2 vs. x2 plot
plot(anscombe$x2, anscombe$y2,
     xlim = c(xmin, xmax),
     ylim = c(ymin, ymax),
     xlab = "x value", ylab = "y value",
     main = "Second dataset")
# Do the same for the y3 vs. x3 plot
plot(anscombe$x3, anscombe$y3,
     xlim = c(xmin, xmax),
     ylim = c(ymin, ymax),
     xlab = "x value", ylab = "y value",
     main = "Third dataset")
# Do the same for the y4 vs. x4 plot
plot(anscombe$x4, anscombe$y4,
     xlim = c(xmin, xmax),
     ylim = c(ymin, ymax),
     xlab = "x value", ylab = "y value",
     main = "Fourth dataset")

Using multiple plots to give multiple views of a dataset As noted in the video, another useful application of multiple plot arrays besides comparison is presenting multiple related views of the same dataset.

This exercise illustrates this idea, giving four views of the same dataset: a plot of the raw data values themselves, a histogram of these data values, a density plot, and a normal QQ-plot.

# Set up a two-by-two plot array
par(mfrow = c(2,2))
# Plot the raw duration data
plot(geyser$duration, main = "Raw data")
# Plot the normalized histogram of the duration data
truehist(geyser$duration, main = "Histogram")
# Plot the density of the duration data
plot(density(geyser$duration), main = "Density")
# Construct the normal QQ-plot of the duration data
qqPlot(geyser$duration, main = "QQ-plot")

Constructing and displaying layout matrices The video illustrated how to set up a layout matrix to be used with the layout() function in creating a plot array. You can think of the layout matrix as the plot pane, where a 0 represents empty space and other numbers represent the plot number, which is determined by the sequence of visualization function calls. For example, a 1 in the layout matrix refers to the visualization that was first called, a 2 refers to the plot of the second visualization call, etc. This exercise asks you to create your own 3 x 2 layout matrix, using the c() function to concatenate numbers into vectors that will form the rows of the matrix.

You will then use the matrix() function to convert these rows into a matrix and apply the layout() function to set up the desired plot array. The convenience function layout.show() can then be used to verify that the plot array has the shape you want.

As reference, feel free to use the slides from the video, which you can access by clicking on the “Slides” tab next to the “R Console” tab. Pay close attention to the example layout matrix and the resulting plot array.

# Use the matrix function to create a matrix with three rows and two columns
layoutMatrix <- matrix(
  c(
    0, 1,
    2, 0,
    0, 3
  ), 
  byrow = TRUE, 
  nrow = 3
)
# Call the layout() function to set up the plot array
layout(layoutMatrix)
# Show where the three plots will go 
layout.show(n = 3)

Creating a triangular array of plots The previous exercise asked you to create a plot array using the layout() function. Recall the layout matrix from the previous exercise:

layoutMatrix [,1] [,2] [1,] 0 1 [2,] 2 0 [3,] 0 3 This exercise asks you to use this array to give three different views of the whiteside data frame.

The first plot, on the upper right of the plot array, shows the relationship of Gas and Temp using all data from whiteside. The second plot, in the center left of the plot array, shows the relationship of the two variables using data where Insul is equal to “Before”. Finally, the third plot, on the lower left of the plot array, shows the relationship using data where Insul is equal to “After”.

The primary motivation for this exercise is that it is not possible to construct a plot array in this format using the mfrow parameter, since the array is not rectangular.

# Set up the plot array
layout(layoutMatrix)
# Construct vectors indexB and indexA
indexB <- which(whiteside$Insul == "Before")
indexA <- which(whiteside$Insul == "After")
# Create plot 1 and add title
plot(whiteside$Temp[indexB], whiteside$Gas[indexB],
     ylim = c(0,8))
title("Before data only")
# Create plot 2 and add title
plot(whiteside$Temp, whiteside$Gas,
     ylim = c(0,8))
title("Complete dataset")
# Create plot 3 and add title
plot(whiteside$Temp[indexA], whiteside$Gas[indexA],
     ylim = c(0,8))
title("After data only")

Creating arrays with different sized plots Besides creating non-rectangular arrays, the layout() function can be used to create plot arrays with different sized component plots – something else that is not possible by setting the par() function’s mfrow parameter.

This exercise illustrates the point, asking you to create a standard scatterplot of the zn versus rad variables from the Boston data frame as a smaller plot in the upper left, with a larger sunflower plot of the same data in the lower right.

# Create row1, row2, and layoutVector
row1 <- c(1, 0, 0)
row2 <- c(0, 2, 2)
layoutVector <- c(row1, rep(row2, 2))
# Convert layoutVector into layoutMatrix
layoutMatrix <- matrix(layoutVector, byrow = TRUE, nrow = 3)
# Set up the plot array
layout(layoutMatrix)
# Plot scatterplot
plot(Boston$rad, Boston$zn)
# Plot sunflower plot
sunflowerplot(Boston$rad, Boston$zn)

Some plot functions also return useful information As shown in the video, calling the barplot() function has the side effect of creating the plot we want, but it also returns a numerical vector with the center positions of each bar in the plot. This value is returned invisibly so we don’t normally see it, but we can capture it with an assignment statement.

These return values can be especially useful when we want to overlay text on the bars of a horizontal barplot. Then, we capture the return values and use them as the y parameter in a subsequent call to the text() function, allowing us to place the text at whatever x position we want but overlaid in the middle of each horizontal bar. This exercise asks you to construct a horizontal barplot that exploits these possibilities.

Feel free to reference a similar example in the slides by clicking on the “Slides” tab next to the “R Console” tab.

# Create a table of Cylinders frequencies
tbl <- table(Cars93$Cylinders)
# Generate a horizontal barplot of these frequencies
mids <- barplot(tbl, horiz = TRUE, 
                col = "transparent",
                names.arg = "")
# Add names labels with text()
text(20, mids, names(tbl))
# Add count labels with text()
text(35, mids, as.numeric(tbl))

Using the symbols() function to display relations between more than two variables The scatterplot allows us to see how one numerical variable changes with the values of a second numerical variable. The symbols() function allows us to extend scatterplots to show the influence of other variables.

This function is called with the variables x and y that define a scatterplot, along with another argument that specifies one of several possible shapes. Here, you are asked to use the circles argument to create a bubbleplot where each data point is represented by a circle whose radius depends on the third variable specified by the value of this argument.

# Call symbols() to create the default bubbleplot
symbols(Cars93$Horsepower, Cars93$MPG.city,
        circles = sqrt(Cars93$Price))

# Repeat, with the inches argument specified
symbols(Cars93$Horsepower, Cars93$MPG.city,
        circles = sqrt(Cars93$Price),
        inches = 0.1)

Saving plot results as files In an interactive R session, we typically generate a collection of different plots, often using the results to help us decide how to proceed with our analysis. This is particularly true in the early phases of an exploratory data analysis, but once we have generated a plot we want to share with others, it is important to save it in an external file.

R provides support for saving graphical results in several different external file formats, including jpeg, png, tiff, or pdf files. In addition, we can incorporate graphical results into external documents, using tools like the Sweave() function or the knitr package. One particularly convenient way of doing this is to create an R Markdown document, an approach that forms the basis for another DataCamp course.

Because png files can be easily shared and viewed as e-mail attachments and incorporated into many slide preparation packages (e.g. Microsoft Powerpoint), this exercise asks you to create a plot and save it as a png file. The basis for this process is the png() function, which specifies the name of the png file to be generated and sets up a special environment that captures all graphical output until we exit this environment with the dev.off() command.

# Call png() with the name of the file we want to create
png("bubbleplot.png")
# Re-create the plot from the last exercise
symbols(Cars93$Horsepower, Cars93$MPG.city,
        circles = sqrt(Cars93$Price),
        inches = 0.1)
# Save our file and return to our interactive session
dev.off()
null device 
          1 
# Verify that we have created the file
list.files(pattern = "png")
[1] "bubbleplot.png"

Iliinsky and Steele’s 12 recommended colors This exercise asks you to create a horizontal barplot that shows Iliinsky and Steele’s set of recommended 12 colors, in descending order of desirability from the top of the plot to the bottom. Also, the first six “more preferred” colors are displayed with longer bars to visually emphasize their preferred status over the other six.

Code is provided to create the character vector IScolors with the names of the 12 colors recommended by Iliinsky and Steele, in their recommended order. We’ve also created the numeric vector barWidths containing the value 2 for the first six Iliinsky and Steele colors and the value 1 for the next six.

In this exercise, you’ll use the barplot() function to create the horizontal barplot shown in the preceeding figure, with the color names to the left of the bars and each bar drawn in the indicated color.

# Iliinsky and Steele color name vector
IScolors <- c("red", "green", "yellow", "blue",
              "black", "white", "pink", "cyan",
              "gray", "orange", "brown", "purple")
# Create the data for the barplot
barWidths <- c(rep(2, 6), rep(1, 6))
# Recreate the horizontal barplot with colored bars
barplot(rev(barWidths), horiz = TRUE,
        col = rev(IScolors), axes = F,
        names.arg = rev(IScolors), las = 1)

Using color to enhance a bubbleplot In a previous exercise, you saw how the symbols() function could be used to generate a bubbleplot showing the relationship between three variables (specifically, Horsepower, MPG.city, and Price from the Cars93 data frame). There, the basic format was a scatterplot of MPG.city versus Horsepower, with points represented as bubbles, sized by Price.

Here, you are asked to create a variation on this plot, using the factor variable Cylinders to determine both the size and the color of the bubbles. To do this, note that as.numeric(Cars93$Cylinders) generates a sequence of numerical values from 1 to 6 that specify the six unique levels of the Cylinders factor.

The point of this exercise is to show that, in cases where color is an option, the clarity of this bubbleplot can be improved substantially through the use of color in addition to symbol size. Since the Cylinders variable exhibits six unique values, six colors are required to make this enhancement, so the top six colors recommended by Iliinsky and Steele are used here.

# Iliinsky and Steele color name vector
IScolors <- c("red", "green", "yellow", "blue",
              "black", "white", "pink", "cyan",
              "gray", "orange", "brown", "purple")
# Create the `cylinderLevel` variable
cylinderLevels <- as.numeric(Cars93$Cylinders)
# Create the colored bubbleplot
symbols(Cars93$Horsepower, Cars93$MPG.city, 
        circles = cylinderLevels, inches = 0.2, 
        bg = IScolors[cylinderLevels])

Using color to enhance stacked barplots The most common barplot consists of a collection of vertical bars, each representing some characteristic of one of a finite number of datasets or data subsets. Several previous exercises have illustrated the utility of the somewhat less common horizontal barplot, useful in part because it allows text to be displayed horizontally across the bars, as illustrated in Exercise 1.

Another useful variant of the standard bar plot is the stacked bar plot, where each bar in the plot is partitioned into segments characterizing portions of the data characterized by the bar. Stacked bar plots can also be generated using the barplot() function. Here, each bar is specified by a matrix whose columns specify the heights of the segments in each bar.

By default, the barplot() function generates stacked bar plots using different shades of gray for the different segments of each bar in the plot. The point of this exercise is to show that, if we can use it, color can be a more effective alternative.

# Create a table of Cylinders by Origin
tbl <- table(Cars93$Cylinders, Cars93$Origin)
# Create the default stacked barplot
barplot(tbl)

# Enhance this plot with color
barplot(tbl, col = IScolors)

The tabplot package and grid graphics The tabplot package allows you to tap into the power of grid graphics without explicit knowledge of how the system works under the hood. The main function in tabplot is tableplot(), developed to visualize data distributions and relationships between variables in large datasets.

Specifically, the tableplot() function constructs a set of side-by-side horizontal barplots, one for each variable. This function works best when viewing up to about 10 variables at a time, for datasets with arbitrarily many records. In this exercise, you are asked to apply this function to a dataset with just under 68,000 records and 11 variables.

The tableplot() function is called with a data frame and, if no optional arguments are specified, it selects the first data column as the reference variable. This variable can be of any type, but the display is easiest to explain when it’s numeric, as in the example considered here.

For further details, refer to the vignette Visualization of large datasets with tabplot that accompanies the help files for the tabplot package.

# Load the insuranceData package
library(insuranceData)
# Use the data() function to load the dataCar data frame
data(dataCar)
# Load the tabplot package
suppressPackageStartupMessages(library(tabplot))
# Generate the default tableplot() display
tableplot(dataCar)

A lattice graphics example Another package built on grid graphics is lattice, but unlike tabplot, lattice is a general-purpose graphics package that provides alternative implementations of many of the plotting functions available in base graphics. Specific examples include scatterplots with the xyplot() function, bar charts with the barchart() function, and boxplots with the bwplot() function.

One important difference between lattice graphics and base graphics is that similar functions available in both graphics systems often produce very different results when applied to the same data. As a specific example, the bwplot() function creates horizontal boxplots, while the default result of the boxplot() is a vertical boxplot display.

Another more important difference between lattice and base graphics is that lattice graphics supports conditional plots that show the separate relationships between variables within different groups. This capability is illustrated in this exercise, where you are asked to construct a plot showing the relationship between the variables calories and sugars from the UScereal data frame, conditional on the value of the shelf variable.

# Load the lattice package
library(lattice)
# Use xyplot() to construct the conditional scatterplot
xyplot(calories ~ sugars | as.factor(shelf), data = UScereal)

A ggplot2 graphics example This final exercise provides an introduction to the ggplot2 graphics package. Like the lattice package, the ggplot2 package is also based on grid graphics and it also represents a general purpose graphics package.

The unique feature of the ggplot2 package is that it is based on the grammar of graphics, a systematic approach to building and modifying graphical displays, starting with a basic graphics element and refining it through the addition of successive modifiers.

This exercise provides a simple illustration of the approach. Specifically, you are asked to use ggplot2 to, first, create a simple scatterplot of MPG.city versus Horsepower from the Cars93 data frame. Next, you are asked to add a simple modifier that adds color based on the value of the Cylinders variable. Finally, you are asked to convert this result into a colored bubble plot, with both bubble sizes and colors determined by the Cylinders variable.

The primary purpose of this exercise is to give you a flavor of the ggplot2 package. DataCamp offers several courses dedicated to using this popular graphics package to generate high-quality data visualizations.

# Load the ggplot2 package
library(ggplot2)
# Create the basic plot (not displayed): basePlot
basePlot <- ggplot(Cars93, aes(x = Horsepower, y = MPG.city))
# Display the basic scatterplot
basePlot + 
  geom_point()

# Color the points by Cylinders value
basePlot + 
  geom_point(colour = IScolors[Cars93$Cylinders])

# Make the point sizes also vary with Cylinders value
basePlot + 
  geom_point(colour = IScolors[Cars93$Cylinders], 
             size = as.numeric(Cars93$Cylinders))

LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIGluIFIiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkNyZWF0aW5nIGFuIGV4cGxvcmF0b3J5IHBsb3QgYXJyYXkKSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIGNvbnN0cnVjdCBhIHNpbXBsZSBleHBsb3JhdG9yeSBwbG90IGZyb20gYSBkYXRhIGZyYW1lIHRoYXQgZ2l2ZXMgdmFsdWVzIGZvciB0aHJlZSB2YXJpYWJsZXMsIHJlY29yZGVkIG92ZXIgdHdvIHdpbnRlciBoZWF0aW5nIHNlYXNvbnMuIFRoZSB2YXJpYWJsZXMgYXJlOgoKVGVtcDogYSBtZWFzdXJlIG9mIHRoZSBvdXRzaWRlIHRlbXBlcmF0dXJlIGR1cmluZyBvbmUgd2VlawpHYXM6IHRoZSBhbW91bnQgb2YgaGVhdGluZyBnYXMgY29uc3VtZWQgZHVyaW5nIHRoYXQgd2VlawpJbnN1bDogYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIHR3byB2YWx1ZXMsIGluZGljYXRpbmcgd2hldGhlciB0aGUgbWVhc3VyZW1lbnRzIHdlcmUgbWFkZSBiZWZvcmUgb3IgYWZ0ZXIgYW4gaW5zdWxhdGlvbiB1cGdyYWRlIHdhcyBtYWRlIHRvIHRoZSBob3VzZQoKYGBge3J9CiMgTG9hZCBNQVNTIHBhY2thZ2UKbGlicmFyeShNQVNTKQoKIyBQbG90IHdoaXRlc2lkZSBkYXRhCnBsb3Qod2hpdGVzaWRlKQpgYGAKCkNyZWF0aW5nIGFuIGV4cGxhbmF0b3J5IHNjYXR0ZXJwbG90CkluIGNvbnN0cmFzdCB0byB0aGUgZXhwbG9yYXRvcnkgYW5hbHlzaXMgcGxvdCB5b3UgY3JlYXRlZCBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGEgc2ltcGxlIGV4cGxhbmF0b3J5IHNjYXR0ZXJwbG90LCBzdWl0YWJsZSBmb3Igc2hhcmluZyB3aXRoIG90aGVycy4KCkhlcmUsIGl0IGlzIGltcG9ydGFudCB0byBtYWtlIGVkaXRvcmlhbCBjaG9pY2VzIGluIGNvbnN0cnVjdGluZyB0aGlzIHBsb3QsIHJhdGhlciB0aGFuIGRlcGVuZGluZyBlbnRpcmVseSBvbiBkZWZhdWx0IG9wdGlvbnMuIEluIHBhcnRpY3VsYXIsIHRoZSBpbXBvcnRhbnQgZWRpdG9yaWFsIGFzcGVjdHMgb2YgdGhpcyBwbG90IGFyZTogZmlyc3QsIHRoZSB2YXJpYWJsZXMgdG8gYmUgcGxvdHRlZCwgYW5kIHNlY29uZCwgdGhlIGF4aXMgbGFiZWxzLCB3aGljaCBhcmUgc3BlY2lmaWVkIGFzIHN0cmluZ3MgdG8gdGhlIHhsYWIgYW5kIHlsYWIgYXJndW1lbnRzIHRvIHRoZSBwbG90KCkgZnVuY3Rpb24uCgpgYGB7cn0KIyBQbG90IEdhcyB2cy4gVGVtcApwbG90KHdoaXRlc2lkZSRUZW1wLCB3aGl0ZXNpZGUkR2FzLAogICAgeGxhYiA9ICJPdXRzaWRlIHRlbXBlcmF0dXJlIiwgeWxhYiA9ICJIZWF0aW5nIGdhcyBjb25zdW1wdGlvbiIpCmBgYAoKVGhlIHBsb3QoKSBmdW5jdGlvbiBpcyBnZW5lcmljCk9uZSBvZiB0aGUga2V5IGZlYXR1cmVzIG9mIHRoZSBwbG90KCkgZnVuY3Rpb24gaXMgdGhhdCBpdCBpcyBnZW5lcmljLCBtZWFuaW5nIHRoYXQgdGhlIHJlc3VsdHMgb2YgYXBwbHlpbmcgdGhlIGZ1bmN0aW9uIGRlcGVuZCBvbiB0aGUgbmF0dXJlIG9mIHRoZSBvYmplY3QgdG8gd2hpY2ggaXQgaXMgYXBwbGllZC4KCkluIHRoZSBmaXJzdCBleGVyY2lzZSBvZiB0aGlzIGNoYXB0ZXIsIGFwcGx5aW5nIHRoZSBwbG90KCkgZnVuY3Rpb24gdG8gdGhlIHdoaXRlc2lkZSBkYXRhIGZyYW1lIHJlc3VsdGVkIGluIGEgcGxvdCBhcnJheS4gSGVyZSwgd2Ugb2J0YWluIGEgZnVuZGFtZW50YWxseSBkaWZmZXJlbnQga2luZCBvZiByZXN1bHQgd2hlbiB3ZSBhcHBseSB0aGUgc2FtZSBmdW5jdGlvbiB0byBJbnN1bCwgYSBmYWN0b3IgdmFyaWFibGUgZnJvbSB0aGUgc2FtZSBkYXRhIGZyYW1lLgoKYGBge3J9CiMgQXBwbHkgdGhlIHBsb3QoKSBmdW5jdGlvbiB0byBJbnN1bApwbG90KHdoaXRlc2lkZSRJbnN1bCkKYGBgCgpBZGRpbmcgZGV0YWlscyB0byBhIHBsb3QgdXNpbmcgcG9pbnQgc2hhcGVzLCBjb2xvciwgYW5kIHJlZmVyZW5jZSBsaW5lcwpBZGRpbmcgYWRkaXRpb25hbCBkZXRhaWxzIHRvIHlvdXIgZXhwbGFuYXRvcnkgcGxvdHMgY2FuIGhlbHAgZW1waGFzaXplIGNlcnRhaW4gYXNwZWN0cyBvZiB5b3VyIGRhdGEuIEZvciBleGFtcGxlLCBieSBzcGVjaWZ5aW5nIHRoZSBwY2ggYW5kIGNvbCBhcmd1bWVudHMgdG8gdGhlIHBsb3QoKSBmdW5jdGlvbiwgeW91IGNhbiBhZGQgZGlmZmVyZW50IHBvaW50IHNoYXBlcyBhbmQgY29sb3JzIHRvIHNob3cgaG93IGRpZmZlcmVudCB2YXJpYWJsZXMgb3Igc3Vic2V0cyBvZiB5b3VyIGRhdGEgcmVsYXRlIHRvIGVhY2ggb3RoZXIuIEluIGFkZGl0aW9uLCB5b3UgY2FuIGFkZCBhIG5ldyBzZXQgb2YgcG9pbnRzIHRvIHlvdXIgZXhpc3Rpbmcgc2NhdHRlcnBsb3Qgd2l0aCB0aGUgcG9pbnRzKCkgZnVuY3Rpb24sIGFuZCBhZGQgcmVmZXJlbmNlIGxpbmVzIHdpdGggdGhlIGFibGluZSgpIGZ1bmN0aW9uLgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byB1c2UgdGhlc2UgbWV0aG9kcyB0byBjcmVhdGUgYW4gZW5oYW5jZWQgc2NhdHRlcnBsb3QgdGhhdCBlZmZlY3RpdmVseSBzaG93cyBob3cgdGhyZWUgdmFyaWFibGVzIGluIHRoZSBDYXJzOTMgZGF0YSBmcmFtZSByZWxhdGUgdG8gZWFjaCBvdGhlci4gVGhlc2UgdmFyaWFibGVzIGFyZToKClByaWNlOiB0aGUgYXZlcmFnZSBzYWxlIHByaWNlIGZvciBhIGNhcgpNYXguUHJpY2U6IHRoZSBoaWdoZXN0IHJlY29yZGVkIHByaWNlIGZvciB0aGF0IGNhcgpNaW4uUHJpY2U6IHRoZSBsb3dlc3QgcmVjb3JkZWQgcHJpY2UgZm9yIHRoYXQgY2FyCgpgYGB7cn0KIyBMb2FkIHRoZSBNQVNTIHBhY2thZ2UKbGlicmFyeShNQVNTKQoKIyBQbG90IE1heC5QcmljZSB2cy4gUHJpY2UgYXMgcmVkIHRyaWFuZ2xlcwpwbG90KENhcnM5MyRQcmljZSxDYXJzOTMkTWF4LlByaWNlLCBwY2ggPSAxNywgY29sID0gInJlZCIpCgojIEFkZCBNaW4uUHJpY2UgdnMuIFByaWNlIGFzIGJsdWUgY2lyY2xlcwpwb2ludHMoIENhcnM5MyRQcmljZSxDYXJzOTMkTWluLlByaWNlLCBwY2ggPSAxNiwgY29sID0gImJsdWUiKQoKIyBBZGQgYW4gZXF1YWxpdHkgcmVmZXJlbmNlIGxpbmUgd2l0aCBhYmxpbmUoKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBsdHkgPSAyKQpgYGAKCkNyZWF0aW5nIG11bHRpcGxlIHBsb3QgYXJyYXlzCllvdSBjYW4gcGxvdCBtdWx0aXBsZSBncmFwaHMgb24gYSBzaW5nbGUgcGFuZSB1c2luZyB0aGUgcGFyKCkgZnVuY3Rpb24gd2l0aCBpdHMgbWZyb3cgcGFyYW1ldGVyLiBGb3IgZXhhbXBsZSwgcGFyKG1mcm93ID0gYygxLCAyKSkgY3JlYXRlcyBhIHBsb3QgYXJyYXkgd2l0aCAxIHJvdyBhbmQgMiBjb2x1bW5zLCBhbGxvd2luZyB5b3UgdG8gdmlldyB0d28gZ3JhcGhzIHNpZGUtYnktc2lkZS4gVGhpcyB3YXksIHlvdSBjYW4gY29tcGFyZSBhbmQgY29udHJhc3QgZGlmZmVyZW50IGRhdGFzZXRzIG9yIGRpZmZlcmVudCB2aWV3cyBvZiB0aGUgc2FtZSBkYXRhc2V0LiBUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGNvbXBhcmUgdHdvIHZpZXdzIG9mIHRoZSBBbmltYWxzMiBkYXRhc2V0IGZyb20gdGhlIHJvYnVzdGJhc2UgcGFja2FnZSwgZGlmZmVyaW5nIGluIGhvdyBpdHMgdmFyaWFibGVzIGFyZSByZXByZXNlbnRlZC4KClRoZSBvYmplY3RpdmUgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBlbXBoYXNpemUgdGhhdCB0aGUgb3JpZ2luYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIGhhdmUgaW4gYSBkYXRhc2V0IGlzIG5vdCBhbHdheXMgdGhlIGJlc3Qgb25lIGZvciB2aXN1YWxpemF0aW9uIG9yIGFuYWx5c2lzLiBCeSByZXByZXNlbnRpbmcgdGhlIG9yaWdpbmFsIHZhcmlhYmxlcyBpbiBsb2cgc2NhbGUsIGZvciBleGFtcGxlLCB3ZSBjYW4gYmV0dGVyIHNlZSBhbmQgdW5kZXJzdGFuZCB0aGUgZGF0YS4KCmBgYHtyfQojIExvYWQgdGhlIHJvYnVzdGJhc2UgcGFja2FnZQpsaWJyYXJ5KHJvYnVzdGJhc2UpCgojIFNldCB1cCB0aGUgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkKcGFyKG1mcm93ID0gYygxLDIpKQoKIyBGaXJzdCBwbG90OiBicmFpbiB2cy4gYm9keSBpbiBpdHMgb3JpZ2luYWwgZm9ybQpwbG90KEFuaW1hbHMyJGJvZHksIEFuaW1hbHMyJGJyYWluKQoKIyBBZGQgdGhlIGZpcnN0IHRpdGxlCnRpdGxlKCJPcmlnaW5hbCByZXByZXNlbnRhdGlvbiIpCgojIFNlY29uZCBwbG90OiBsb2ctbG9nIHBsb3Qgb2YgYnJhaW4gdnMuIGJvZHkKcGxvdChBbmltYWxzMiRib2R5LCBBbmltYWxzMiRicmFpbiwgbG9nPSJ4eSIpCgojIEFkZCB0aGUgc2Vjb25kIHRpdGxlCnRpdGxlKCJMb2ctbG9nIHBsb3QiKQpgYGAKCkF2b2lkIHBpZSBjaGFydHMKVGhlIHNhbWUgZGF0YXNldCBjYW4gYmUgZGlzcGxheWVkIG9yIHN1bW1hcml6ZWQgaW4gbWFueSBkaWZmZXJlbnQgd2F5cywgYnV0IHNvbWUgYXJlIG11Y2ggbW9yZSBzdWl0YWJsZSB0aGFuIG90aGVycy4KCkRlc3BpdGUgdGhlaXIgZ2VuZXJhbCBwb3B1bGFyaXR5LCBwaWUgY2hhcnRzIGFyZSBvZnRlbiBhIHBvb3IgY2hvaWNlLiBUaG91Z2ggUiBhbGxvd3MgcGllIGNoYXJ0cyB3aXRoIHRoZSBwaWUoKSBmdW5jdGlvbiwgZXZlbiB0aGUgaGVscCBmaWxlIGZvciB0aGlzIGZ1bmN0aW9uIGFyZ3VlcyBhZ2FpbnN0IHRoZWlyIHVzZS4gU3BlY2lmaWNhbGx5LCB0aGUgaGVscCBmaWxlIGluY2x1ZGVzIGEgIk5vdGUiIHRoYXQgYmVnaW5zIHdpdGggdGhlIHdvcmRzOiAiUGllIGNoYXJ0cyBhcmUgYSB2ZXJ5IGJhZCB3YXkgb2YgZGlzcGxheWluZyBpbmZvcm1hdGlvbi4iCgpCYXIgY2hhcnRzIGFyZSBhIHJlY29tbWVuZGVkIGFsdGVybmF0aXZlIGFuZCwgaW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIHNlZSB3aHkuCgpgYGB7cn0KIyBMb2FkIHRoZSBpbnN1cmFuY2VEYXRhIHBhY2thZ2UKbGlicmFyeShpbnN1cmFuY2VEYXRhKQoKIyBVc2UgdGhlIGRhdGEoKSBmdW5jdGlvbiB0byBnZXQgdGhlIGRhdGFDYXIgZGF0YSBmcmFtZQpkYXRhKGRhdGFDYXIpCgojIFNldCB1cCBhIHNpZGUtYnktc2lkZSBwbG90IGFycmF5CnBhcihtZnJvdyA9IGMoMSwgMikpCgojIENyZWF0ZSBhIHRhYmxlIG9mIHZlaF9ib2R5IHJlY29yZCBjb3VudHMgYW5kIHNvcnQKdGJsIDwtIHNvcnQodGFibGUoZGF0YUNhciR2ZWhfYm9keSksCiAgICAgICAgICAgIGRlY3JlYXNpbmcgPSBUUlVFKQoKIyBDcmVhdGUgdGhlIHBpZSBjaGFydCBhbmQgZ2l2ZSBpdCBhIHRpdGxlCnBpZSh0YmwpCnRpdGxlKCJQaWUgY2hhcnQiKQoKIyBDcmVhdGUgdGhlIGJhcnBsb3Qgd2l0aCBwZXJwZW5kaWN1bGFyLCBoYWxmLXNpemVkIGxhYmVscwpiYXJwbG90KHRibCwgbGFzID0gMiwgY2V4Lm5hbWVzID0gMC41KQoKIyBBZGQgYSB0aXRsZQp0aXRsZSgiQmFyIGNoYXJ0IikKYGBgCgpUaGUgaGlzdCgpIGFuZCB0cnVlaGlzdCgpIGZ1bmN0aW9ucwpIaXN0b2dyYW1zIGFyZSBwcm9iYWJseSB0aGUgYmVzdC1rbm93biB3YXkgb2YgbG9va2luZyBhdCBob3cgdGhlIHZhbHVlcyBvZiBhIG51bWVyaWNhbCB2YXJpYWJsZSBhcmUgZGlzdHJpYnV0ZWQgb3ZlciB0aGVpciByYW5nZSwgYW5kIFIgcHJvdmlkZXMgc2V2ZXJhbCBkaWZmZXJlbnQgaGlzdG9ncmFtIGltcGxlbWVudGF0aW9ucy4KClRoZSBwdXJwb3NlIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gaW50cm9kdWNlIHR3byBvZiB0aGVzZToKCmhpc3QoKSBpcyBwYXJ0IG9mIGJhc2UgUiBhbmQgaXRzIGRlZmF1bHQgb3B0aW9uIHlpZWxkcyBhIGhpc3RvZ3JhbSBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIHRpbWVzIGEgcmVjb3JkIGZhbGxzIGludG8gZWFjaCBvZiB0aGUgYmlucyBvbiB3aGljaCB0aGUgaGlzdG9ncmFtIGlzIGJhc2VkLgp0cnVlaGlzdCgpIGlzIGZyb20gdGhlIE1BU1MgcGFja2FnZSBhbmQgc2NhbGVzIHRoZXNlIGNvdW50cyB0byBnaXZlIGFuIGVzdGltYXRlIG9mIHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5LgoKYGBge3J9CiMgU2V0IHVwIGEgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkKcGFyKG1mcm93ID0gYygxLDIpKQoKIyBDcmVhdGUgYSBoaXN0b2dyYW0gb2YgY291bnRzIHdpdGggaGlzdCgpCmhpc3QoQ2FyczkzJEhvcnNlcG93ZXIsIG1haW4gPSAiaGlzdCgpIHBsb3QiKQoKIyBDcmVhdGUgYSBub3JtYWxpemVkIGhpc3RvZ3JhbSB3aXRoIHRydWVoaXN0KCkKdHJ1ZWhpc3QoQ2FyczkzJEhvcnNlcG93ZXIsIG1haW4gPSAidHJ1ZWhpc3QoKSBwbG90IikgCmBgYAoKRGVuc2l0eSBwbG90cyBhcyBzbW9vdGhlZCBoaXN0b2dyYW1zCldoaWxlIHRoZXkgYXJlIHByb2JhYmx5IG5vdCBhcyB3ZWxsIGtub3duIGFzIHRoZSBoaXN0b2dyYW0sIGRlbnNpdHkgZXN0aW1hdGVzIG1heSBiZSByZWdhcmRlZCBhcyBzbW9vdGhlZCBoaXN0b2dyYW1zLCBkZXNpZ25lZCB0byBnaXZlIGEgYmV0dGVyIGVzdGltYXRlIG9mIHRoZSBkZW5zaXR5IGZ1bmN0aW9uIGZvciBhIHJhbmRvbSB2YXJpYWJsZS4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCB1c2UgdGhlIENoaWNrV2VpZ2h0IGRhdGFzZXQsIHdoaWNoIGNvbnRhaW5zIGEgY29sbGVjdGlvbiBvZiBjaGlja3MnIHdlaWdodHMuIFlvdSB3aWxsIGZpcnN0IHNlbGVjdCBmb3IgdGhlIGNoaWNrcyB0aGF0IGFyZSAxNiB3ZWVrcyBvbGQuIFRoZW4sIHlvdSdsbCBjcmVhdGUgYSBoaXN0b2dyYW0gdXNpbmcgdGhlIHRydWVoaXN0KCkgZnVuY3Rpb24sIGFuZCBhZGQgaXRzIGRlbnNpdHkgcGxvdCBvbiB0b3AsIHVzaW5nIHRoZSBsaW5lcygpIGFuZCBkZW5zaXR5KCkgZnVuY3Rpb25zIHdpdGggdGhlaXIgZGVmYXVsdCBvcHRpb25zLiBUaGUgZGVuc2l0eSBwbG90IG9mIHRoaXMgdHlwZSBvZiB2YXJpYWJsZSBpcyBvZnRlbiBleHBlY3RlZCB0byBjb25mb3JtIGFwcHJveGltYXRlbHkgdG8gdGhlIGJlbGwtc2hhcGVkIGN1cnZlLCBvdGhlcndpc2Uga25vd24gYXMgdGhlIEdhdXNzaWFuIGRpc3RyaWJ1dGlvbi4gTGV0J3MgZmluZCBvdXQgd2hldGhlciB0aGF0J3MgdGhlIGNhc2UgZm9yIHRoaXMgZGF0YXNldC4KCmBgYHtyfQojIENyZWF0ZSBpbmRleDE2LCBwb2ludGluZyB0byAxNi13ZWVrIGNoaWNrcwppbmRleDE2IDwtIHdoaWNoKENoaWNrV2VpZ2h0JFRpbWU9PTE2KQoKIyBHZXQgdGhlIDE2LXdlZWsgY2hpY2sgd2VpZ2h0cwp3ZWlnaHRzID0gQ2hpY2tXZWlnaHQkd2VpZ2h0W2luZGV4MTZdCgojIFBsb3QgdGhlIG5vcm1hbGl6ZWQgaGlzdG9ncmFtCnRydWVoaXN0KHdlaWdodHMpCgojIEFkZCB0aGUgZGVuc2l0eSBjdXJ2ZSB0byB0aGUgaGlzdG9ncmFtCmxpbmVzKGRlbnNpdHkod2VpZ2h0cykpIAoKYGBgCgpVc2luZyB0aGUgcXFQbG90KCkgZnVuY3Rpb24gdG8gc2VlIG1hbnkgZGV0YWlscyBpbiBkYXRhCkEgcHJhY3RpY2FsIGxpbWl0YXRpb24gb2YgYm90aCBoaXN0b2dyYW1zIGFuZCBkZW5zaXR5IGVzdGltYXRlcyBpcyB0aGF0LCBpZiB3ZSB3YW50IHRvIGtub3cgd2hldGhlciB0aGUgR2F1c3NpYW4gZGlzdHJpYnV0aW9uIGFzc3VtcHRpb24gaXMgcmVhc29uYWJsZSBmb3Igb3VyIGRhdGEsIGl0IGlzIGRpZmZpY3VsdCB0byB0ZWxsLgoKVGhlIHF1YW50aWxlLXF1YW50aWxlIHBsb3QsIG9yIFFRLXBsb3QsIGlzIGEgdXNlZnVsIGFsdGVybmF0aXZlOiB3ZSBzb3J0IG91ciBkYXRhLCBwbG90IGl0IGFnYWluc3QgYSBzcGVjaWFsbHktZGVzaWduZWQgeC1heGlzIGJhc2VkIG9uIG91ciByZWZlcmVuY2UgZGlzdHJpYnV0aW9uIChlLmcuLCB0aGUgR2F1c3NpYW4gImJlbGwgY3VydmUiKSwgYW5kIGxvb2sgdG8gc2VlIHdoZXRoZXIgdGhlIHBvaW50cyBsaWUgYXBwcm94aW1hdGVseSBvbiBhIHN0cmFpZ2h0IGxpbmUuIEluIFIsIHNldmVyYWwgUVEtcGxvdCBpbXBsZW1lbnRhdGlvbnMgYXJlIGF2YWlsYWJsZSwgYnV0IHRoZSBtb3N0IGNvbnZlbmllbnQgb25lIGlzIHRoZSBxcVBsb3QoKSBmdW5jdGlvbiBpbiB0aGUgY2FyIHBhY2thZ2UuCgpUaGUgZmlyc3QgcGFydCBvZiB0aGlzIGV4ZXJjaXNlIGFwcGxpZXMgdGhpcyBmdW5jdGlvbiB0byB0aGUgMTYtd2VlayBjaGljayB3ZWlnaHQgZGF0YSBjb25zaWRlcmVkIGluIHRoZSBsYXN0IGV4ZXJjaXNlLCB0byBzaG93IHRoYXQgdGhlIEdhdXNzaWFuIGRpc3RyaWJ1dGlvbiBhcHBlYXJzIHRvIGJlIHJlYXNvbmFibGUgaGVyZS4gVGhlIHNlY29uZCBwYXJ0IG9mIHRoZSBleGVyY2lzZSBhcHBsaWVzIHRoaXMgZnVuY3Rpb24gdG8gYW5vdGhlciB2YXJpYWJsZSB3aGVyZSB0aGUgR2F1c3NpYW4gZGlzdHJpYnV0aW9uIGlzIG9idmlvdXNseSBhIHBvb3IgZml0LCBidXQgdGhlIHJlc3VsdHMgYWxzbyBzaG93IHRoZSBwcmVzZW5jZSBvZiByZXBlYXRlZCB2YWx1ZXMgKGZsYXQgc3RyZXRjaGVzIGluIHRoZSBwbG90KSBhbmQgcG9ydGlvbnMgb2YgdGhlIGRhdGEgcmFuZ2Ugd2hlcmUgdGhlcmUgYXJlIG5vIG9ic2VydmF0aW9ucyAodmVydGljYWwgImp1bXBzIiBpbiB0aGUgcGxvdCkuCgpgYGB7cn0KIyBMb2FkIHRoZSBjYXIgcGFja2FnZSB0byBtYWtlIHFxUGxvdCgpIGF2YWlsYWJsZQpsaWJyYXJ5KGNhcikKCiMgQ3JlYXRlIGluZGV4MTYsIHBvaW50aW5nIHRvIDE2LXdlZWsgY2hpY2tzCmluZGV4MTYgPC0gd2hpY2goQ2hpY2tXZWlnaHQkVGltZSA9PSAxNikKCiMgR2V0IHRoZSAxNi13ZWVrIGNoaWNrIHdlaWdodHMKd2VpZ2h0cyA8LSBDaGlja1dlaWdodCR3ZWlnaHRbaW5kZXgxNl0KCiMgU2hvdyB0aGUgbm9ybWFsIFFRLXBsb3Qgb2YgdGhlIGNoaWNrIHdlaWdodHMKcXFQbG90KHdlaWdodHMpCgojIFNob3cgdGhlIG5vcm1hbCBRUS1wbG90IG9mIHRoZSBCb3N0b24kdGF4IGRhdGEKcXFQbG90KEJvc3RvbiR0YXgpCmBgYAoKVGhlIHN1bmZsb3dlcnBsb3QoKSBmdW5jdGlvbiBmb3IgcmVwZWF0ZWQgbnVtZXJpY2FsIGRhdGEKQSBzY2F0dGVycGxvdCByZXByZXNlbnRzIGVhY2ggKHgsIHkpIHBhaXIgaW4gYSBkYXRhc2V0IGJ5IGEgc2luZ2xlIHBvaW50LiBJZiBzb21lIG9mIHRoZXNlIHBhaXJzIGFyZSByZXBlYXRlZCAoaS5lLiBpZiB0aGUgc2FtZSBjb21iaW5hdGlvbiBvZiB4IGFuZCB5IHZhbHVlcyBhcHBlYXJzIG1vcmUgdGhhbiBvbmNlIGFuZCB0aHVzIGxpZSBvbiB0b3Agb2YgZWFjaCBvdGhlciksIHdlIGNhbid0IHNlZSB0aGlzIGluIGEgc2NhdHRlcnBsb3QuIFNldmVyYWwgYXBwcm9hY2hlcyBoYXZlIGJlZW4gZGV2ZWxvcGVkIHRvIGRlYWwgd2l0aCB0aGlzIHByb2JsZW0sIGluY2x1ZGluZyBqaXR0ZXJpbmcsIHdoaWNoIGFkZHMgc21hbGwgcmFuZG9tIHZhbHVlcyB0byBlYWNoIHggYW5kIHkgdmFsdWUsIHNvIHJlcGVhdGVkIHBvaW50cyB3aWxsIGFwcGVhciBhcyBjbHVzdGVycyBvZiBuZWFyYnkgcG9pbnRzLgoKQSB1c2VmdWwgYWx0ZXJuYXRpdmUgdGhhdCBpcyBlcXVhbGx5IGVmZmVjdGl2ZSBpbiByZXByZXNlbnRpbmcgcmVwZWF0ZWQgZGF0YSBwb2ludHMgaXMgdGhlIHN1bmZsb3dlcnBsb3QsIHdoaWNoIHJlcHJlc2VudHMgZWFjaCByZXBlYXRlZCBwb2ludCBieSBhICJzdW5mbG93ZXIsIiB3aXRoIG9uZSAicGV0YWwiIGZvciBlYWNoIHJlcGV0aXRpb24gb2YgYSBkYXRhIHBvaW50LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjb25zdHJ1Y3QgYm90aCBhIHNjYXR0ZXJwbG90IGFuZCBhIHN1bmZsb3dlcnBsb3QgZnJvbSB0aGUgc2FtZSBkYXRhc2V0LCBvbmUgdGhhdCBjb250YWlucyByZXBlYXRlZCBkYXRhIHBvaW50cy4gQ29tcGFyaW5nIHRoZXNlIHBsb3RzIGFsbG93cyB5b3UgdG8gc2VlIGhvdyBtdWNoIGluZm9ybWF0aW9uIGNhbiBiZSBsb3N0IGluIGEgc3RhbmRhcmQgc2NhdHRlcnBsb3Qgd2hlbiBzb21lIGRhdGEgcG9pbnRzIGFwcGVhciBtYW55IHRpbWVzLgoKYGBge3J9CiMgU2V0IHVwIGEgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkKcGFyKG1mcm93ID0gYygxLDIpKQoKIyBDcmVhdGUgdGhlIHN0YW5kYXJkIHNjYXR0ZXJwbG90CnBsb3QoIEJvc3RvbiR6bixCb3N0b24kcmFkKQoKIyBBZGQgdGhlIHRpdGxlCnRpdGxlKCJTdGFuZGFyZCBzY2F0dGVycGxvdCIpCgojIENyZWF0ZSB0aGUgc3VuZmxvd2VycGxvdApzdW5mbG93ZXJwbG90KEJvc3RvbiR6biwgQm9zdG9uJHJhZCkKCiMgQWRkIHRoZSB0aXRsZQp0aXRsZSgiU3VuZmxvd2VyIHBsb3QiKQpgYGAKClVzZWZ1bCBvcHRpb25zIGZvciB0aGUgYm94cGxvdCgpIGZ1bmN0aW9uClRoZSBib3hwbG90KCkgZnVuY3Rpb24gc2hvd3MgaG93IHRoZSBkaXN0cmlidXRpb24gb2YgYSBudW1lcmljYWwgdmFyaWFibGUgeSBkaWZmZXJzIGFjcm9zcyB0aGUgdW5pcXVlIGxldmVscyBvZiBhIHNlY29uZCB2YXJpYWJsZSwgeC4gVG8gYmUgZWZmZWN0aXZlLCB0aGlzIHNlY29uZCB2YXJpYWJsZSBzaG91bGQgbm90IGhhdmUgdG9vIG1hbnkgdW5pcXVlIGxldmVscyAoZS5nLiwgMTAgb3IgZmV3ZXIgaXMgZ29vZDsgbWFueSBtb3JlIHRoYW4gdGhpcyBtYWtlcyB0aGUgcGxvdCBkaWZmaWN1bHQgdG8gaW50ZXJwcmV0KS4KClRoZSBib3hwbG90KCkgZnVuY3Rpb24gYWxzbyBoYXMgYSBudW1iZXIgb2Ygb3B0aW9uYWwgcGFyYW1ldGVycyBhbmQgdGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byB1c2UgdGhyZWUgb2YgdGhlbSB0byBvYnRhaW4gYSBtb3JlIGluZm9ybWF0aXZlIHBsb3Q6Cgp2YXJ3aWR0aCBhbGxvd3MgZm9yIHZhcmlhYmxlLXdpZHRoIGJveHBsb3RzIHRoYXQgc2hvdyB0aGUgZGlmZmVyZW50IHNpemVzIG9mIHRoZSBkYXRhIHN1YnNldHMuCmxvZyBhbGxvd3MgZm9yIGxvZy10cmFuc2Zvcm1lZCB5LXZhbHVlcy4KbGFzIGFsbG93cyBmb3IgbW9yZSByZWFkYWJsZSBheGlzIGxhYmVscy4KVGhpcyBleGVyY2lzZSBhbHNvIGlsbHVzdHJhdGVzIHRoZSB1c2Ugb2YgdGhlIGZvcm11bGEgaW50ZXJmYWNlOiB5IH4geCBpbmRpY2F0ZXMgdGhhdCB3ZSB3YW50IGEgYm94cGxvdCBvZiB0aGUgeSB2YXJpYWJsZSBhY3Jvc3MgdGhlIGRpZmZlcmVudCBsZXZlbHMgb2YgdGhlIHggdmFyaWFibGUuIFNlZSA/Ym94cGxvdCBmb3IgbW9yZSBkZXRhaWxzLgoKYGBge3J9CiMgQ3JlYXRlIGEgdmFyaWFibGUtd2lkdGggYm94cGxvdCB3aXRoIGxvZyB5LWF4aXMgJiBob3Jpem9udGFsIGxhYmVscwpib3hwbG90KGNyaW1+cmFkLCBkYXRhPUJvc3RvbiwgdmFyd2lkdGg9VFJVRSAsIGxvZyA9ICJ5IiwgbGFzID0xKQoKIyBBZGQgYSB0aXRsZQp0aXRsZSgiQ3JpbWUgcmF0ZSB2cy4gcmFkaWFsIGhpZ2h3YXkgaW5kZXgiKQpgYGAKClVzaW5nIHRoZSBtb3NhaWNwbG90KCkgZnVuY3Rpb24KQSBtb3NhaWMgcGxvdCBtYXkgYmUgdmlld2VkIGFzIGEgc2NhdHRlcnBsb3QgYmV0d2VlbiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgYW5kIGl0IGlzIHN1cHBvcnRlZCBpbiBSIHdpdGggdGhlIG1vc2FpY3Bsb3QoKSBmdW5jdGlvbi4KCkFzIHRoaXMgZXhhbXBsZSBzaG93cywgaW4gYWRkaXRpb24gdG8gY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB0aGlzIHBsb3QgY2FuIGFsc28gYmUgdXNlZnVsIGluIHVuZGVyc3RhbmRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG51bWVyaWNhbCB2YXJpYWJsZXMsIGVpdGhlciBpbnRlZ2VyLSBvciByZWFsLXZhbHVlZCwgdGhhdCB0YWtlIG9ubHkgYSBmZXcgZGlzdGluY3QgdmFsdWVzLgoKTW9yZSBzcGVjaWZpY2FsbHksIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY29uc3RydWN0IGEgbW9zYWljIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG51bWVyaWNhbCBjYXJiIGFuZCBjeWwgdmFyaWFibGVzIGZyb20gdGhlIG10Y2FycyBkYXRhIGZyYW1lLCB2YXJpYWJsZXMgdGhhdCBleGhpYml0IDYgYW5kIDMgdW5pcXVlIHZhbHVlcywgcmVzcGVjdGl2ZWx5LgoKYGBge3J9CiMgQ3JlYXRlIGEgbW9zYWljIHBsb3QgdXNpbmcgdGhlIGZvcm11bGEgaW50ZXJmYWNlCm1vc2FpY3Bsb3QoY2FyYn5jeWwsIGRhdGEgPSBtdGNhcnMpIApgYGAKClVzaW5nIHRoZSBiYWdwbG90KCkgZnVuY3Rpb24KQSBzaW5nbGUgYm94IHBsb3QgZ2l2ZXMgYSBncmFwaGljYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJhbmdlIG9mIHZhcmlhdGlvbiBpbiBhIG51bWVyaWNhbCB2YXJpYWJsZSwgYmFzZWQgb24gZml2ZSBudW1iZXJzOgoKVGhlIG1pbmltdW0gYW5kIG1heGltdW0gdmFsdWVzClRoZSBtZWRpYW4gKG9yICJtaWRkbGUiKSB2YWx1ZQpUd28gaW50ZXJtZWRpYXRlIHZhbHVlcyBjYWxsZWQgdGhlIGxvd2VyIGFuZCB1cHBlciBxdWFydGlsZXMKSW4gYWRkaXRpb24sIHRoZSBzdGFuZGFyZCBib3ggcGxvdCBjb21wdXRlcyBhIG5vbWluYWwgZGF0YSByYW5nZSBmcm9tIHRocmVlIG9mIHRoZXNlIG51bWJlcnMgYW5kIGZsYWdzIHBvaW50cyBmYWxsaW5nIG91dHNpZGUgdGhpcyByYW5nZSBhcyBvdXRsaWVycywgcmVwcmVzZW50aW5nIHRoZW0gYXMgZGlzdGluY3QgcG9pbnRzLgoKVGhlIGJhZyBwbG90IGV4dGVuZHMgdGhpcyByZXByZXNlbnRhdGlvbiB0byB0d28gbnVtZXJpY2FsIHZhcmlhYmxlcywgc2hvd2luZyB0aGVpciByZWxhdGlvbnNoaXAsIGJvdGggd2l0aGluIHR3by1kaW1lbnNpb25hbCAiYmFncyIgY29ycmVzcG9uZGluZyB0byB0aGUgImJveCIgaW4gdGhlIHN0YW5kYXJkIGJveHBsb3QsIGFuZCBpbmRpY2F0aW5nIG91dGx5aW5nIHBvaW50cyBvdXRzaWRlIHRoZXNlIGxpbWl0cy4KClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY29uc3RydWN0LCBmaXJzdCwgc2lkZS1ieS1zaWRlIGJveCBwbG90cyBvZiB0aGUgTWluLlByaWNlIGFuZCBNYXguUHJpY2UgdmFyaWFibGVzIGZyb20gdGhlIG10Y2FycyBkYXRhc2V0LCBhbmQgdGhlbiB0byB1c2UgdGhlIGJhZ3Bsb3QoKSBmdW5jdGlvbiBmcm9tIHRoZSBhcGxwYWNrIHBhY2thZ2UgdG8gY29uc3RydWN0IHRoZSBjb3JyZXNwb25kaW5nIGJhZyBwbG90LgoKYGBge3J9CiMgQ3JlYXRlIGEgc2lkZS1ieS1zaWRlIGJveHBsb3Qgc3VtbWFyeQpwYXIobWZyb3cgPSBjKDEsMikpCmJveHBsb3QoQ2FyczkzJE1pbi5QcmljZSwgQ2FyczkzJE1heC5QcmljZSkKCgojIExvYWQgYXBscGFjayB0byBtYWtlIHRoZSBiYWdwbG90KCkgZnVuY3Rpb24gYXZhaWxhYmxlCmxpYnJhcnkoYXBscGFjaykKCiMgQ3JlYXRlIGEgYmFncGxvdCBmb3IgdGhlIHNhbWUgdHdvIHZhcmlhYmxlcwpiYWdwbG90KENhcnM5MyRNaW4uUHJpY2UsIENhcnM5MyRNYXguUHJpY2UgLCBjZXggPSAxLjIpCgojIEFkZCBhbiBlcXVhbGl0eSByZWZlcmVuY2UgbGluZQphYmxpbmUoMCwxLGx0eSA9IDIpCmBgYAoKUGxvdHRpbmcgY29ycmVsYXRpb24gbWF0cmljZXMgd2l0aCB0aGUgY29ycnBsb3QoKSBmdW5jdGlvbgpDb3JyZWxhdGlvbiBtYXRyaWNlcyB3ZXJlIGludHJvZHVjZWQgaW4gdGhlIHZpZGVvIGFzIGEgdXNlZnVsIHRvb2wgZm9yIG9idGFpbmluZyBhIHByZWxpbWluYXJ5IHZpZXcgb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBtdWx0aXBsZSBudW1lcmljYWwgdmFyaWFibGVzLgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byB1c2UgdGhlIGNvcnJwbG90KCkgZnVuY3Rpb24gZnJvbSB0aGUgY29ycnBsb3QgcGFja2FnZSB0byB2aXN1YWxpemUgdGhpcyBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBudW1lcmljYWwgdmFyaWFibGVzIGZyb20gdGhlIFVTY2VyZWFsIGRhdGEgZnJhbWUgaW4gdGhlIE1BU1MgcGFja2FnZS4gUmVjYWxsIHRoYXQgaW4gdGhpcyB2ZXJzaW9uIG9mIHRoZXNlIHBsb3RzLCBlbGxpcHNlcyB0aGF0IGFyZSB0aGluIGFuZCBlbG9uZ2F0ZWQgaW5kaWNhdGUgYSBsYXJnZSBjb3JyZWxhdGlvbiB2YWx1ZSBiZXR3ZWVuIHRoZSBpbmRpY2F0ZWQgdmFyaWFibGVzLCB3aGlsZSBlbGxpcHNlcyB0aGF0IGFyZSBuZWFybHkgY2lyY3VsYXIgaW5kaWNhdGUgY29ycmVsYXRpb25zIG5lYXIgemVyby4KCmBgYHtyfQojIExvYWQgdGhlIGNvcnJwbG90IGxpYnJhcnkgZm9yIHRoZSBjb3JycGxvdCgpIGZ1bmN0aW9uCmxpYnJhcnkoY29ycnBsb3QpCgojIEV4dHJhY3QgdGhlIG51bWVyaWNhbCB2YXJpYWJsZXMgZnJvbSBVU2NlcmVhbApudW1lcmljYWxWYXJzID0gVVNjZXJlYWxbMjoxMF0KCiMgQ29tcHV0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciB0aGVzZSB2YXJpYWJsZXMKY29yck1hdCA8LSBjb3IobnVtZXJpY2FsVmFycykKCiMgR2VuZXJhdGUgdGhlIGNvcnJlbGF0aW9uIGVsbGlwc2UgcGxvdApjb3JycGxvdChjb3JyTWF0LCBtZXRob2QgPSAiZWxsaXBzZSIpCmBgYAoKQnVpbGRpbmcgYW5kIHBsb3R0aW5nIHJwYXJ0KCkgbW9kZWxzCkl0IHdhcyBub3RlZCBpbiB0aGUgdmlkZW8gdGhhdCBkZWNpc2lvbiB0cmVlcyByZXByZXNlbnQgYSBwb3B1bGFyIGZvcm0gb2YgcHJlZGljdGl2ZSBtb2RlbCBiZWNhdXNlIHRoZXkgYXJlIGVhc3kgdG8gdmlzdWFsaXplIGFuZCBleHBsYWluLiBJdCB3YXMgYWxzbyBub3RlZCB0aGF0IHRoZSBycGFydCBwYWNrYWdlIGlzIHByb2JhYmx5IHRoZSBtb3N0IHBvcHVsYXIgb2Ygc2V2ZXJhbCBSIHBhY2thZ2VzIHRoYXQgY2FuIGJlIHVzZWQgdG8gYnVpbGQgYW5kIHZpc3VhbGl6ZSB0aGVzZSBtb2RlbHMuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvLCBmaXJzdCwgYnVpbGQgYSBkZWNpc2lvbiB0cmVlIG1vZGVsIHVzaW5nIHRoZSBycGFydCgpIGZ1bmN0aW9uIGZyb20gdGhpcyBwYWNrYWdlLCBhbmQgdGhlbiBkaXNwbGF5IHRoZSByZXN1bHRpbmcgbW9kZWwgc3RydWN0dXJlIHVzaW5nIHRoZSBnZW5lcmljIGZ1bmN0aW9ucyBwbG90KCkgYW5kIHRleHQoKS4KCmBgYHtyfQojIExvYWQgdGhlIHJwYXJ0IGxpYnJhcnkKbGlicmFyeShycGFydCkKCiMgRml0IGFuIHJwYXJ0IG1vZGVsIHRvIHByZWRpY3QgbWVkdiBmcm9tIGFsbCBvdGhlciBCb3N0b24gdmFyaWFibGVzCnRyZWVfbW9kZWwgPC0gcnBhcnQobWVkdn4uLCBkYXRhID0gQm9zdG9uKQoKIyBQbG90IHRoZSBzdHJ1Y3R1cmUgb2YgdGhpcyBkZWNpc2lvbiB0cmVlIG1vZGVsCnBsb3QodHJlZV9tb2RlbCkKCiMgQWRkIGxhYmVscyB0byB0aGlzIHBsb3QKdGV4dCh0cmVlX21vZGVsLCBjZXggPSAwLjcpCmBgYAoKSW50cm9kdWN0aW9uIHRvIHRoZSBwYXIoKSBmdW5jdGlvbgpZb3UgYWxyZWFkeSBzYXcgaG93IHRoZSBtZnJvdyBwYXJhbWV0ZXIgdG8gdGhlIHBhcigpIGZ1bmN0aW9uIGNvdWxkIGJlIHVzZWQgdG8gcGxvdCBtdWx0aXBsZSBncmFwaHMgaW4gb25lIHBhbmUuIFRoZSBwYXIoKSBmdW5jdGlvbiBhbHNvIGFsbG93cyB5b3UgdG8gc2V0IG1hbnkgb3RoZXIgZ3JhcGhpY3MgcGFyYW1ldGVycywgd2hvc2UgdmFsdWVzIHdpbGwgcmVtYWluIGluIGVmZmVjdCB1bnRpbCB0aGV5IGFyZSByZXNldCBieSBhIHN1YnNlcXVlbnQgcGFyKCkgY2FsbC4KClNwZWNpZmljYWxseSwgYSBjYWxsIHRvIHRoZSBwYXIoKSBmdW5jdGlvbiB3aXRoIG5vIHBhcmFtZXRlcnMgc3BlY2lmaWVkIHdpbGwgcmV0dXJuIGEgbGlzdCB3aG9zZSBlbGVtZW50IG5hbWVzIGVhY2ggc3BlY2lmeSBhIGdyYXBoaWNzIHBhcmFtZXRlciBhbmQgd2hvc2UgZWxlbWVudCB2YWx1ZXMgc3BlY2lmeSB0aGUgY29ycmVzcG9uZGluZyBkZWZhdWx0IHZhbHVlcyBvZiB0aGVzZSBwYXJhbWV0ZXJzLiBUaGVzZSBwYXJhbWV0ZXJzIG1heSBiZSBzZXQgYnkgYSBjYWxsIGluIHRoZSBmb3JtIHBhcihuYW1lID0gdmFsdWUpIHdoZXJlIG5hbWUgaXMgdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlciB0byBiZSBzZXQgYW5kIHZhbHVlIGlzIHRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGlzIHBhcmFtZXRlci4KClRoZSBwdXJwb3NlIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZ2l2ZSBhbiBpZGVhIG9mIHdoYXQgdGhlc2UgZ3JhcGhpY3MgcGFyYW1ldGVycyBhcmUuIEluIHRoZSBzdWJzZXF1ZW50IGV4ZXJjaXNlcyB3ZSdsbCBzaG93IGhvdyBzb21lIG9mIHRoZXNlIHBhcmFtZXRlcnMgY2FuIGJlIHVzZWQgdG8gZW5oYW5jZSBwbG90IHJlc3VsdHMuCgpgYGB7cn0KIyBBc3NpZ24gdGhlIHJldHVybiB2YWx1ZSBmcm9tIHRoZSBwYXIoKSBmdW5jdGlvbiB0byBwbG90X3BhcnMKcGxvdF9wYXJzIDwtIHBhcigpCgojIERpc3BsYXkgdGhlIG5hbWVzIG9mIHRoZSBwYXIoKSBmdW5jdGlvbidzIGxpc3QgZWxlbWVudHMKbmFtZXMocGxvdF9wYXJzKQoKIyBEaXNwbGF5IHRoZSBudW1iZXIgb2YgcGFyKCkgZnVuY3Rpb24gbGlzdCBlbGVtZW50cwpsZW5ndGgocGxvdF9wYXJzKQpgYGAKCkV4cGxvcmluZyB0aGUgdHlwZSBvcHRpb24KT25lIG9mIHRoZSBpbXBvcnRhbnQgZ3JhcGhpY3MgcGFyYW1ldGVycyB0aGF0IGNhbiBiZSBzZXQgd2l0aCB0aGUgcGFyKCkgZnVuY3Rpb24gaXMgbWZyb3csIHdoaWNoIHNwZWNpZmllcyB0aGUgbnVtYmVycyBvZiByb3dzIGFuZCBjb2x1bW5zIGluIGFuIGFycmF5IG9mIHBsb3RzLiBWYWxpZCB2YWx1ZXMgZm9yIHRoaXMgcGFyYW1ldGVyIGFyZSB0d28tZWxlbWVudCBudW1lcmljYWwgdmVjdG9ycywgd2hvc2UgZmlyc3QgZWxlbWVudCBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiByb3dzIGluIHRoZSBwbG90IGFycmF5IGFuZCB0aGUgc2Vjb25kIGVsZW1lbnQgc3BlY2lmaWVzIHRoZSBudW1iZXIgb2Ygcm93cy4KCkEgbW9yZSBkZXRhaWxlZCBkaXNjdXNzaW9uIG9mIHVzaW5nIHRoZSBtZnJvdyBwYXJhbWV0ZXIgaXMgZ2l2ZW4gaW4gQ2hhcHRlciA0IG9mIHRoaXMgY291cnNlLiBGb3Igbm93LCBub3RlIHRoYXQgdG8gc3BlY2lmeSBhIHBsb3QgYXJyYXkgd2l0aCB0aHJlZSByb3dzIGFuZCBvbmUgY29sdW1uLCB0aGUgY29tbWFuZCB3b3VsZCBiZSBwYXIobWZyb3cgPSBjKDMsIDEpKS4KClRoZSBmb2xsb3dpbmcgZXhlcmNpc2UgYWxzbyBpbnRyb2R1Y2VzIHRoZSB0eXBlIHBhcmFtZXRlciBmb3IgdGhlIHBsb3QoKSBjb21tYW5kLCB3aGljaCBzcGVjaWZpZXMgaG93IHRoZSBwbG90IGlzIGRyYXduLiBUaGUgc3BlY2lmaWMgdHlwZSB2YWx1ZXMgdXNlZCBoZXJlIGFyZToKCiJwIiBmb3IgInBvaW50cyIKImwiIGZvciAibGluZXMiCiJvIiBmb3IgIm92ZXJsYWlkIiAoaS5lLiwgbGluZXMgb3ZlcmxhaWQgd2l0aCBwb2ludHMpCiJzIiBmb3IgInN0ZXBzIgoKYGBge3J9CiMgU2V0IHVwIGEgMi1ieS0yIHBsb3QgYXJyYXkKcGFyKG1mcm93ID0gYygyLDIpKQoKIyBQbG90IHRoZSBBbmltYWxzMiBicmFpbiB3ZWlnaHQgZGF0YSBhcyBwb2ludHMKcGxvdChBbmltYWxzMiRicmFpbiwgdHlwZSA9ICJwIikKCiMgQWRkIHRoZSB0aXRsZQp0aXRsZSgicG9pbnRzIikKCiMgUGxvdCB0aGUgYnJhaW4gd2VpZ2h0cyB3aXRoIGxpbmVzCnBsb3QoQW5pbWFsczIkYnJhaW4sIHR5cGUgPSAibCIpCgojIEFkZCB0aGUgdGl0bGUKdGl0bGUoImxpbmVzIikKCiMgUGxvdCB0aGUgYnJhaW4gd2VpZ2h0cyBhcyBsaW5lcyBvdmVybGFpZCB3aXRoIHBvaW50cwpwbG90KEFuaW1hbHMyJGJyYWluLCB0eXBlID0gIm8iKQoKIyBBZGQgdGhlIHRpdGxlCnRpdGxlKCJvdmVybGFpZCIpCgojIFBsb3QgdGhlIGJyYWluIHdlaWdodHMgYXMgc3RlcHMKcGxvdChBbmltYWxzMiRicmFpbiwgdHlwZSA9ICJzIikKCiMgQWRkIHRoZSB0aXRsZQp0aXRsZSgic3RlcHMiKQpgYGAKClRoZSBzdXJwcmlzaW5nIHV0aWxpdHkgb2YgdGhlIHR5cGUgIm4iIG9wdGlvbgpUaGUgdHlwZSA9ICJuIiBvcHRpb24gd2FzIGRpc2N1c3NlZCBpbiB0aGUgdmlkZW8gYW5kIHRoaXMgZXhlcmNpc2UgcHJvdmlkZXMgYSBzaW1wbGUgZXhhbXBsZS4gVGhpcyBvcHRpb24gaXMgZXNwZWNpYWxseSB1c2VmdWwgaXMgd2hlbiB3ZSBhcmUgcGxvdHRpbmcgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgb24gYSBjb21tb24gc2V0IG9mIGF4ZXMuIEluIHN1Y2ggY2FzZXMsIHdlIGNhbiBjb21wdXRlIHJhbmdlcyBmb3IgdGhlIHgtIGFuZCB5LWF4ZXMgc28gdGhhdCBhbGwgZGF0YSBwb2ludHMgd2lsbCBhcHBlYXIgb24gdGhlIHBsb3QsIGFuZCB0aGVuIGFkZCB0aGUgZGF0YSB3aXRoIHN1YnNlcXVlbnQgY2FsbHMgdG8gcG9pbnRzKCkgb3IgbGluZXMoKSBhcyBhcHByb3ByaWF0ZS4KClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gZ2VuZXJhdGUgYSBwbG90IHRoYXQgY29tcGFyZXMgbWlsZWFnZSB2cy4gaG9yc2Vwb3dlciBkYXRhIGZyb20gdHdvIGRpZmZlcmVudCBzb3VyY2VzOiB0aGUgbXRjYXJzIGRhdGEgZnJhbWUgaW4gdGhlIGRhdGFzZXRzIHBhY2thZ2UgYW5kIHRoZSBDYXJzOTMgZGF0YSBmcmFtZSBpbiB0aGUgTUFTUyBwYWNrYWdlLiBUbyBkaXN0aW5ndWlzaCB0aGUgZGlmZmVyZW50IHJlc3VsdHMgZnJvbSB0aGVzZSBkYXRhIHNvdXJjZXMsIHRoZSBncmFwaGljcyBwYXJhbWV0ZXIgcGNoIGlzIHVzZWQgdG8gc3BlY2lmeSBwb2ludCBzaGFwZXMuIFNlZSA/cG9pbnRzIGZvciBhIGNvbXByZWhlbnNpdmUgbGlzdCBvZiBzb21lIHBjaCB2YWx1ZXMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgcG9pbnQgc2hhcGVzLgoKYGBge3J9CiMgQ29tcHV0ZSBtYXhfaHAKbWF4X2hwIDwtIG1heChDYXJzOTMkSG9yc2Vwb3dlciwgbXRjYXJzJGhwKQoKIyBDb21wdXRlIG1heF9tcGcKbWF4X21wZyA8LSBtYXgoQ2FyczkzJE1QRy5jaXR5LCBDYXJzOTMkTVBHLmhpZ2h3YXksCiAgICAgICAgICAgICAgIG10Y2FycyRtcGcpCgojIENyZWF0ZSBwbG90IHdpdGggdHlwZSA9ICJuIiAgICAgICAgICAgICAgIApwbG90KENhcnM5MyRIb3JzZXBvd2VyLCBDYXJzOTMkTVBHLmNpdHksCiAgICAgdHlwZSA9ICJuIiwgeGxpbSA9IGMoMCwgbWF4X2hwKSwKICAgICB5bGltID0gYygwLCBtYXhfbXBnKSwgeGxhYiA9ICJIb3JzZXBvd2VyIiwKICAgICB5bGFiID0gIk1pbGVzIHBlciBnYWxsb24iKQoKIyBBZGQgb3BlbiBjaXJjbGVzIHRvIHBsb3QKcG9pbnRzKG10Y2FycyRocCwgbXRjYXJzJG1wZywgcGNoID0gMSkKCiMgQWRkIHNvbGlkIHNxdWFyZXMgdG8gcGxvdApwb2ludHMoQ2FyczkzJEhvcnNlcG93ZXIsIENhcnM5MyRNUEcuY2l0eSwKICAgICAgIHBjaCA9IDE1KQoKIyBBZGQgb3BlbiB0cmlhbmdsZXMgdG8gcGxvdApwb2ludHMoQ2FyczkzJEhvcnNlcG93ZXIsIENhcnM5MyRNUEcuaGlnaHdheSwKICAgICAgIHBjaCA9IDIpCmBgYAoKVGhlIGxpbmVzKCkgZnVuY3Rpb24gYW5kIGxpbmUgdHlwZXMKQXMgbm90ZWQgaW4gQ2hhcHRlciAyLCBudW1lcmljYWwgZGF0YSBpcyBvZnRlbiBhc3N1bWVkIHRvIGNvbmZvcm0gYXBwcm94aW1hdGVseSB0byBhIEdhdXNzaWFuIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiwgY2hhcmFjdGVyaXplZCBieSB0aGUgYmVsbCBjdXJ2ZS4gT25lIHBvaW50IG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gc2hvdyB3aGF0IHRoaXMgYmVsbCBjdXJ2ZSBsb29rcyBsaWtlIGZvciBleGFjdGx5IEdhdXNzaWFuIGRhdGEgYW5kIHRoZSBvdGhlciBpcyB0byBzaG93IGhvdyB0aGUgbGluZXMoKSBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBhZGQgbGluZXMgdG8gYW4gZXhpc3RpbmcgcGxvdC4KClRoZSBjdXJ2ZXMgeW91IGFyZSBhc2tlZCB0byBkcmF3IGhlcmUgaGF2ZSB0aGUgc2FtZSBiYXNpYyBzaGFwZSBidXQgZGlmZmVyIGluIHRoZWlyIGRldGFpbHMgKHNwZWNpZmljYWxseSwgdGhlIG1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zIG9mIHRoZXNlIEdhdXNzaWFuIGRpc3RyaWJ1dGlvbnMgYXJlIGRpZmZlcmVudCkuIEZvciB0aGlzIHJlYXNvbiwgaXQgaXMgdXNlZnVsIHRvIGRyYXcgdGhlc2UgY3VydmVzIHdpdGggZGlmZmVyZW50IGxpbmUgdHlwZXMgdG8gaGVscCB1cyBkaXN0aW5ndWlzaCB0aGVtLgoKTm90ZSB0aGF0IGxpbmUgdHlwZXMgYXJlIHNldCBieSB0aGUgbHR5IGFyZ3VtZW50LCB3aXRoIHRoZSBkZWZhdWx0IHZhbHVlIGx0eSA9IDEgc3BlY2lmeWluZyBzb2xpZCBsaW5lcywgbHR5ID0gMiBzcGVjaWZ5aW5nIGRhc2hlZCBsaW5lcywgYW5kIGx0eSA9IDMgc3BlY2lmeWluZyBkb3R0ZWQgbGluZXMuIEFsc28gbm90ZSB0aGF0IHRoZSBsd2QgYXJndW1lbnQgc3BlY2lmaWVzIHRoZSByZWxhdGl2ZSB3aWR0aC4KCmBgYHtyfQojIENyZWF0ZSB0aGUgbnVtZXJpY2FsIHZlY3RvciB4CnggPC0gc2VxKDAsIDEwLCBsZW5ndGggPSAyMDApCgojIENvbXB1dGUgdGhlIEdhdXNzaWFuIGRlbnNpdHkgZm9yIHggd2l0aCBtZWFuIDIgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiAwLjIKZ2F1c3MxIDwtIGRub3JtKHgsIG1lYW4gPSAyLCBzZCA9IDAuMikKCiMgQ29tcHV0ZSB0aGUgR2F1c3NpYW4gZGVuc2l0eSB3aXRoIG1lYW4gNCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIDAuNQpnYXVzczIgPC0gZG5vcm0oeCwgbWVhbiA9IDQsIHNkID0gMC41KQoKIyBQbG90IHRoZSBmaXJzdCBHYXVzc2lhbiBkZW5zaXR5CnBsb3QoeCwgZ2F1c3MxLCB0eXBlID0gImwiLCB5bGFiID0gIkdhdXNzaWFuIHByb2JhYmlsaXR5IGRlbnNpdHkiKQoKIyBBZGQgbGluZXMgZm9yIHRoZSBzZWNvbmQgR2F1c3NpYW4gZGVuc2l0eQpsaW5lcyh4LCBnYXVzczIsIGx0eSA9IDIsIGx3ZCA9IDMpCmBgYAoKVGhlIHBvaW50cygpIGZ1bmN0aW9uIGFuZCBwb2ludCB0eXBlcwpPbmUgYWR2YW50YWdlIG9mIHNwZWNpZnlpbmcgdGhlIHBjaCBhcmd1bWVudCBsb2NhbGx5IGlzIHRoYXQsIGluIGEgY2FsbCB0byBmdW5jdGlvbnMgbGlrZSBwbG90KCkgb3IgcG9pbnRzKCksIGxvY2FsIHNwZWNpZmljYXRpb24gYWxsb3dzIHVzIHRvIG1ha2UgcGNoIGRlcGVuZCBvbiBhIHZhcmlhYmxlIGluIG91ciBkYXRhc2V0LiBUaGlzIHByb3ZpZGVzIGEgc2ltcGxlIHdheSBvZiBpbmRpY2F0aW5nIGRpZmZlcmVudCBkYXRhIHN1YnNldHMgd2l0aCBkaWZmZXJlbnQgcG9pbnQgc2hhcGVzIG9yIHN5bWJvbHMuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGdlbmVyYXRlIHR3byBwbG90cyBvZiBtcGcgdnMuIGhwIGZyb20gdGhlIG10Y2FycyBkYXRhIGZyYW1lIGluIHRoZSBkYXRhc2V0cyBwYWNrYWdlLiBUaGUgZmlyc3QgcGxvdCBzcGVjaWZpZXMgdGhlIHBvaW50IHNoYXBlcyB1c2luZyBudW1lcmljYWwgdmFsdWVzIG9mIHRoZSBwY2ggYXJndW1lbnQgZGVmaW5lZCBieSB0aGUgY3lsIHZhcmlhYmxlIGluIHRoZSBtdGNhcnMgZGF0YSBmcmFtZS4gVGhlIHNlY29uZCBwbG90IGlsbHVzdHJhdGVzIHRoZSBmYWN0IHRoYXQgcGNoIGNhbiBhbHNvIGJlIHNwZWNpZmllZCBhcyBhIHZlY3RvciBvZiBzaW5nbGUgY2hhcmFjdGVycywgY2F1c2luZyBlYWNoIHBvaW50IHRvIGJlIGRyYXduIGFzIHRoZSBjb3JyZXNwb25kaW5nIGNoYXJhY3Rlci4KCmBgYHtyfQojIENyZWF0ZSBhbiBlbXB0eSBwbG90IHVzaW5nIHR5cGUgPSAibiIKcGxvdChtdGNhcnMkaHAsbXRjYXJzJG1wZywgIHR5cGUgPSAibiIsIHhsYWIgPSAiSG9yc2Vwb3dlciIsIHlsYWIgPSAiR2FzIG1pbGVhZ2UiKQoKIyBBZGQgcG9pbnRzIHdpdGggc2hhcGVzIGRldGVybWluZWQgYnkgY3lsaW5kZXIgbnVtYmVyCnBvaW50cyhtdGNhcnMkaHAsbXRjYXJzJG1wZywgIHBjaCA9IGFzLm51bWVyaWMobXRjYXJzJGN5bCkpCgojIENyZWF0ZSBhIHNlY29uZCBlbXB0eSBwbG90CnBsb3QobXRjYXJzJGhwLG10Y2FycyRtcGcsICB0eXBlID0gIm4iLCB4bGFiID0gIkhvcnNlcG93ZXIiLCB5bGFiID0gIkdhcyBtaWxlYWdlIikKCgojIEFkZCBwb2ludHMgd2l0aCBzaGFwZXMgYXMgY3lsaW5kZXIgY2hhcmFjdGVycwpwb2ludHMobXRjYXJzJGhwLCBtdGNhcnMkbXBnLCAgcGNoID0gYXMuY2hhcmFjdGVyKG10Y2FycyRjeWwpKQpgYGAKCkFkZGluZyB0cmVuZCBsaW5lcyBmcm9tIGxpbmVhciByZWdyZXNzaW9uIG1vZGVscwpUaGUgbG93LWxldmVsIHBsb3QgZnVuY3Rpb24gYWJsaW5lKCkgYWRkcyBhIHN0cmFpZ2h0IGxpbmUgdG8gYW4gZXhpc3RpbmcgcGxvdC4gVGhpcyBsaW5lIGlzIHNwZWNpZmllZCBieSBhbiBpbnRlcmNlcHQgcGFyYW1ldGVyIGEgYW5kIGEgc2xvcGUgcGFyYW1ldGVyIGIsIGFuZCB0aGUgc2ltcGxlc3Qgd2F5IHRvIHNldCB0aGVzZSBwYXJhbWV0ZXJzIGlzIGRpcmVjdGx5LiBGb3IgZXhhbXBsZSwgdGhlIGNvbW1hbmQgYWJsaW5lKGEgPSAwLCBiID0gMSkgYWRkcyBhbiBlcXVhbGl0eSByZWZlcmVuY2UgbGluZSB3aXRoIHplcm8gaW50ZXJjZXB0IGFuZCB1bml0IChpLmUuIDEpIHNsb3BlOiBwb2ludHMgZm9yIHdoaWNoIHkgPSB4IGZhbGwgb24gdGhpcyByZWZlcmVuY2UgbGluZSwgd2hpbGUgcG9pbnRzIHdpdGggeSA+IHggZmFsbCBhYm92ZSBpdCwgYW5kIHBvaW50cyB3aXRoIHkgPCB4IGZhbGwgYmVsb3cgaXQuCgpBbiBhbHRlcm5hdGl2ZSB3YXkgb2Ygc3BlY2lmeWluZyB0aGVzZSBwYXJhbWV0ZXJzIGlzIHRocm91Z2ggYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB0aGF0IGRldGVybWluZXMgdGhlbSBmcm9tIGRhdGEuIE9uZSBjb21tb24gYXBwbGljYXRpb24gaXMgdG8gZ2VuZXJhdGUgYSBzY2F0dGVycGxvdCBvZiB5IHZlcnN1cyB4LCB0aGVuIGZpdCBhIGxpbmVhciBtb2RlbCB0aGF0IHByZWRpY3RzIHkgZnJvbSB4LCBhbmQgZmluYWxseSBjYWxsIGFibGluZSgpIHRvIGFkZCB0aGlzIGJlc3QgZml0IGxpbmUgdG8gdGhlIHBsb3QuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGRvIHRoaXMgZm9yIHRoZSBHYXMgdmVyc3VzIFRlbXAgZGF0YSBmcm9tIHRoZSB3aGl0ZXNpZGUgZGF0YSBmcmFtZSBpbiB0aGUgTUFTUyBwYWNrYWdlLiBUaGUgc3RhbmRhcmQgUiBmdW5jdGlvbiB0aGF0IGZpdHMgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIGlzIGxtKCksIHdoaWNoIHN1cHBvcnRzIHRoZSBmb3JtdWxhIGludGVyZmFjZS4gVGh1cywgdG8gZml0IGEgbGluZWFyIG1vZGVsIHRoYXQgcHJlZGljdHMgeSBmcm9tIHggaW4gdGhlIGRhdGEgZnJhbWUgZGYsIHRoZSBjYWxsIHdvdWxkIGJlIGxtKHkgfiB4LCBkYXRhID0gZGYpLiBUaGlzIGNhbGwgcmV0dXJucyBhIGxpbmVhciBtb2RlbCBvYmplY3QsIHdoaWNoIGNhbiB0aGVuIGJlIHBhc3NlZCBhcyBhbiBhcmd1bWVudCB0byB0aGUgYWJsaW5lKCkgZnVuY3Rpb24gdG8gZHJhdyB0aGUgZGVzaXJlZCBsaW5lIG9uIG91ciBwbG90LgoKYGBge3J9CiMgQnVpbGQgYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIHdoaXRlc2lkZSBkYXRhCmxpbmVhcl9tb2RlbCA8LSBsbShHYXN+VGVtcCwgZGF0YSA9IHdoaXRlc2lkZSkKCiMgQ3JlYXRlIGEgR2FzIHZzLiBUZW1wIHNjYXR0ZXJwbG90IGZyb20gdGhlIHdoaXRlc2lkZSBkYXRhCnBsb3Qod2hpdGVzaWRlJFRlbXAsIHdoaXRlc2lkZSRHYXMpCgojIFVzZSBhYmxpbmUoKSB0byBhZGQgdGhlIGxpbmVhciByZWdyZXNzaW9uIGxpbmUKYWJsaW5lKGxpbmVhcl9tb2RlbCwgbHR5ID0yKQpgYGAKClVzaW5nIHRoZSB0ZXh0KCkgZnVuY3Rpb24gdG8gbGFiZWwgcGxvdCBmZWF0dXJlcwpPbmUgb2YgdGhlIG1haW4gdXNlcyBvZiB0aGUgdGV4dCgpIGZ1bmN0aW9uIGlzIHRvIGFkZCBpbmZvcm1hdGl2ZSBsYWJlbHMgdG8gYSBkYXRhIHBsb3QuIFRoZSB0ZXh0KCkgZnVuY3Rpb24gdGFrZXMgdGhyZWUgYXJndW1lbnRzOgoKeCwgd2hpY2ggc3BlY2lmaWVzIHRoZSB2YWx1ZSBmb3IgdGhlIHggdmFyaWFibGUsCnksIHdoaWNoIHNwZWNpZmllcyB0aGUgdmFsdWUgZm9yIHRoZSB5IHZhcmlhYmxlLCBhbmQKbGFiZWwsIHdoaWNoIHNwZWNpZmllcyB0aGUgbGFiZWwgZm9yIHRoZSB4LXkgdmFsdWUgcGFpci4KVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBmaXJzdCBjcmVhdGUgYSBzY2F0dGVycGxvdCBvZiBjaXR5IGdhcyBtaWxlYWdlIHZlcnN1cyBob3JzZXBvd2VyIGZyb20gdGhlIENhcnM5MyBkYXRhLCB0aGVuIGlkZW50aWZ5IGFuIGludGVyZXN0aW5nIHN1YnNldCBvZiB0aGUgZGF0YSAoaS5lLiB0aGUgMy1jeWxpbmRlciBjYXJzKSBhbmQgbGFiZWwgdGhlc2UgcG9pbnRzLiBZb3Ugd2lsbCBmaW5kIHRoYXQgYXNzaWduaW5nIGEgdmVjdG9yIHRvIHRoZSB4LCB5LCBhbmQgbGFiZWwgYXJndW1lbnRzIHRvIHRleHQoKSB3aWxsIHJlc3VsdCBpbiBsYWJlbGluZyBtdWx0aXBsZSBwb2ludHMgYXQgb25jZS4KCmBgYHtyfQojIENyZWF0ZSBNUEcuY2l0eSB2cy4gSG9yc2Vwb3dlciBwbG90IHdpdGggc29saWQgc3F1YXJlcwpwbG90KENhcnM5MyRIb3JzZXBvd2VyLCBDYXJzOTMkTVBHLmNpdHksIHBjaCA9IDE1KQoKIyBDcmVhdGUgaW5kZXgzLCBwb2ludGluZyB0byAzLWN5bGluZGVyIGNhcnMKaW5kZXgzIDwtIHdoaWNoKENhcnM5MyRDeWxpbmRlcnMgPT0zKQoKIyBBZGQgdGV4dCBnaXZpbmcgbmFtZXMgb2YgY2FycyBuZXh0IHRvIGRhdGEgcG9pbnRzCnRleHQoeCA9IENhcnM5MyRIb3JzZXBvd2VyW2luZGV4M10sIAogICAgIHkgPSBDYXJzOTMkTVBHLmNpdHlbaW5kZXgzXSwKICAgICBsYWJlbHMgPSBDYXJzOTMkTWFrZVtpbmRleDNdLAogICAgIGFkaiA9IDApCgoKYGBgCgpBZGp1c3RpbmcgdGV4dCBwb3NpdGlvbiwgc2l6ZSwgYW5kIGZvbnQKVGhlIHByZXZpb3VzIGV4ZXJjaXNlIGFkZGVkIGV4cGxhbmF0b3J5IHRleHQgdG8gYSBzY2F0dGVycGxvdC4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBleGVyY2lzZSBpcyB0byBpbXByb3ZlIHRoaXMgcGxvdCBieSBtb2RpZnlpbmcgdGhlIHRleHQgcGxhY2VtZW50LCBpbmNyZWFzaW5nIHRoZSB0ZXh0IHNpemUsIGFuZCBkaXNwbGF5aW5nIHRoZSB0ZXh0IGluIGJvbGRmYWNlLgoKSXQgd2FzIG5vdGVkIHRoYXQgdGhlIGFkaiBhcmd1bWVudCB0byB0aGUgdGV4dCgpIGZ1bmN0aW9uIGRldGVybWluZXMgdGhlIGhvcml6b250YWwgcGxhY2VtZW50IG9mIHRoZSB0ZXh0IGFuZCBpdCBjYW4gdGFrZSBhbnkgdmFsdWUgYmV0d2VlbiAwIGFuZCAxLiBJbiBmYWN0LCB0aGlzIGFyZ3VtZW50IGNhbiB0YWtlIHZhbHVlcyBvdXRzaWRlIHRoaXMgcmFuZ2UuIFRoYXQgaXMsIG1ha2luZyB0aGlzIHZhbHVlIG5lZ2F0aXZlIGNhdXNlcyB0aGUgdGV4dCB0byBzdGFydCB0byB0aGUgcmlnaHQgb2YgdGhlIHNwZWNpZmllZCB4IHBvc2l0aW9uLiBTaW1pbGFybHksIG1ha2luZyBhZGogZ3JlYXRlciB0aGFuIDEgY2F1c2VzIHRoZSB0ZXh0IHRvIGVuZCB0byB0aGUgbGVmdCBvZiB0aGUgeCBwb3NpdGlvbi4KCkFub3RoZXIgdXNlZnVsIG9wdGlvbmFsIGFyZ3VtZW50IGZvciB0aGUgdGV4dCgpIGZ1bmN0aW9uIGlzIGNleCwgd2hpY2ggc2NhbGVzIHRoZSBkZWZhdWx0IHRleHQgc2l6ZS4gQXMgYSBzcGVjaWZpYyBleGFtcGxlLCBzZXR0aW5nIGNleCA9IDEuNSBpbmNyZWFzZXMgdGhlIHRleHQgc2l6ZSBieSA1MCBwZXJjZW50LCByZWxhdGl2ZSB0byB0aGUgZGVmYXVsdCB2YWx1ZS4gU2ltaWxhcmx5LCBzcGVjaWZ5aW5nIGNleCA9IDAuOCByZWR1Y2VzIHRoZSB0ZXh0IHNpemUgYnkgMjAgcGVyY2VudC4KCkZpbmFsbHksIHRoZSB0aGlyZCBvcHRpb25hbCBwYXJhbWV0ZXIgdXNlZCBoZXJlIGlzIGZvbnQsIHdoaWNoIGNhbiBiZSB1c2VkIHRvIHNwZWNpZnkgb25lIG9mIGZvdXIgdGV4dCBmb250czogZm9udCA9IDEgaXMgdGhlIGRlZmF1bHQgdGV4dCBmb250IChuZWl0aGVyIGl0YWxpYyBub3IgYm9sZCksIGZvbnQgPSAyIHNwZWNpZmllcyBib2xkIGZhY2UgdGV4dCwgZm9udCA9IDMgc3BlY2lmaWVzIGl0YWxpYyB0ZXh0LCBhbmQgZm9udCA9IDQgc3BlY2lmaWVzIGJvdGggYm9sZCBhbmQgaXRhbGljIHRleHQuCgpgYGB7cn0KIyBQbG90IE1QRy5jaXR5IHZzLiBIb3JzZXBvd2VyIGFzIG9wZW4gY2lyY2xlcwpwbG90KENhcnM5MyRIb3JzZXBvd2VyLCBDYXJzOTMkTVBHLmNpdHksIHBjaCA9IDEpCgojIENyZWF0ZSBpbmRleDMsIHBvaW50aW5nIHRvIDMtY3lsaW5kZXIgY2FycwppbmRleDMgPC0gd2hpY2goQ2FyczkzJEN5bGluZGVycyA9PSAzKQoKIyBIaWdobGlnaHQgMy1jeWxpbmRlciBjYXJzIGFzIHNvbGlkIGNpcmNsZXMKcG9pbnRzKENhcnM5MyRIb3JzZXBvd2VyW2luZGV4M10sCiAgICAgICBDYXJzOTMkTVBHLmNpdHlbaW5kZXgzXSwKICAgICAgIHBjaCA9IDE2KQoKIyBBZGQgY2FyIG5hbWVzLCBvZmZzZXQgZnJvbSBwb2ludHMsIHdpdGggbGFyZ2VyIGJvbGQgdGV4dAp0ZXh0KENhcnM5MyRIb3JzZXBvd2VyW2luZGV4M10sCiAgICAgQ2FyczkzJE1QRy5jaXR5W2luZGV4M10sCiAgICAgQ2FyczkzJE1ha2VbaW5kZXgzXSwKICAgICBhZGogPSAtMC4yLCBjZXggPSAxLjIsIGZvbnQgPSA0KQpgYGAKClJvdGF0aW5nIHRleHQgd2l0aCB0aGUgc3J0IGFyZ3VtZW50CkluIGFkZGl0aW9uIHRvIHRoZSBvcHRpb25hbCBhcmd1bWVudHMgdXNlZCBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzLCB0aGUgdGV4dCgpIGZ1bmN0aW9uIGFsc28gc3VwcG9ydHMgYSBudW1iZXIgb2Ygb3RoZXIgb3B0aW9uYWwgYXJndW1lbnRzIHRoYXQgY2FuIGJlIHVzZWQgdG8gZW5oYW5jZSB0aGUgdGV4dC4gVGhpcyBleGVyY2lzZSB1c2VzIHRoZSBjZXggYXJndW1lbnQgdG8gcmVkdWNlIHRoZSB0ZXh0IHNpemUgYW5kIGludHJvZHVjZXMgdHdvIG5ldyBhcmd1bWVudHMuIFRoZSBmaXJzdCBpcyB0aGUgY29sIGFyZ3VtZW50IHRoYXQgc3BlY2lmaWVzIHRoZSBjb2xvciB1c2VkIHRvIGRpc3BsYXkgdGhlIHRleHQsIGFuZCB0aGUgc2Vjb25kIGlzIHRoZSBzcnQgYXJndW1lbnQgdGhhdCBhbGxvd3MgdXMgdG8gcm90YXRlIHRoZSB0ZXh0LgoKQ29sb3IgaGFzIGJlZW4gdXNlZCBpbiBzZXZlcmFsIG9mIHRoZSBwcmV2aW91cyBleGVyY2lzZXMgdG8gc3BlY2lmeSBwb2ludCBjb2xvcnMsIGFuZCB0aGUgZWZmZWN0aXZlIHVzZSBvZiBjb2xvciBpcyBkaXNjdXNzZWQgZnVydGhlciBpbiBDaGFwdGVyIDUuIE9uZSBvZiB0aGUgcG9pbnRzIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gc2hvdyB0aGF0IHRoZSBzcGVjaWZpY2F0aW9uIG9mIHRleHQgY29sb3Igd2l0aCB0aGUgdGV4dCgpIGZ1bmN0aW9uIGlzIGVzc2VudGlhbGx5IHRoZSBzYW1lIGFzIHRoZSBzcGVjaWZpY2F0aW9uIG9mIHBvaW50IGNvbG9yIHdpdGggdGhlIHBsb3QoKSBmdW5jdGlvbi4gQXMgYSBzcGVjaWZpYyBleGFtcGxlLCBzZXR0aW5nIGNvbCA9ICJncmVlbiIgaW4gdGhlIHRleHQoKSBmdW5jdGlvbiBjYXVzZXMgdGhlIHRleHQgdG8gYXBwZWFyIGluIGdyZWVuLiBJZiBjb2wgaXMgbm90IHNwZWNpZmllZCwgdGhlIHRleHQgYXBwZWFycyBpbiB0aGUgZGVmYXVsdCBjb2xvciBzZXQgYnkgdGhlIHBhcigpIGZ1bmN0aW9uLCB3aGljaCBpcyB0eXBpY2FsbHkgYmxhY2suCgpUaGUgc3J0IHBhcmFtZXRlciBhbGxvd3MgdXMgdG8gcm90YXRlIHRoZSB0ZXh0IHRocm91Z2ggYW4gYW5nbGUgc3BlY2lmaWVkIGluIGRlZ3JlZXMuIFRoZSB0eXBpY2FsIGRlZmF1bHQgdmFsdWUgKHNldCBieSB0aGUgcGFyKCkgZnVuY3Rpb24pIGlzIDAsIGNhdXNpbmcgdGhlIHRleHQgdG8gYXBwZWFyIGhvcml6b250YWxseSwgcmVhZGluZyBmcm9tIGxlZnQgdG8gcmlnaHQuIFNwZWNpZnlpbmcgc3J0ID0gOTAgY2F1c2VzIHRoZSB0ZXh0IHRvIGJlIHJvdGF0ZWQgOTAgZGVncmVlcyBjb3VudGVyLWNsb2Nrd2lzZSBzbyB0aGF0IGl0IHJlYWRzIGZyb20gYm90dG9tIHRvIHRvcCBpbnN0ZWFkIG9mIGxlZnQgdG8gcmlnaHQuCgpgYGB7cn0KIyBQbG90IEdhcyB2cy4gVGVtcCBhcyBzb2xpZCB0cmlhbmdsZXMKcGxvdCh3aGl0ZXNpZGUkVGVtcCwgd2hpdGVzaWRlJEdhcywgcGNoID0gMTcpCgojIENyZWF0ZSBpbmRleEIsIHBvaW50aW5nIHRvICJCZWZvcmUiIGRhdGEKaW5kZXhCIDwtIHdoaWNoKHdoaXRlc2lkZSRJbnN1bCA9PSAiQmVmb3JlIikKCiMgQ3JlYXRlIGluZGV4QSwgcG9pbnRpbmcgdG8gIkFmdGVyIiBkYXRhCmluZGV4QSA8LSB3aGljaCh3aGl0ZXNpZGUkSW5zdWwgPT0gIkFmdGVyIikKCiMgQWRkICJCZWZvcmUiIHRleHQgaW4gYmx1ZSwgcm90YXRlZCAzMCBkZWdyZWVzLCA4MCUgc2l6ZQp0ZXh0KHggPSB3aGl0ZXNpZGUkVGVtcFtpbmRleEJdLCB5ID0gd2hpdGVzaWRlJEdhc1tpbmRleEJdLAogICAgIGxhYmVscyA9ICJCZWZvcmUiLCBjb2wgPSAiYmx1ZSIsIHNydCA9IDMwLCBjZXggPSAwLjgpCgojIEFkZCAiQWZ0ZXIiIHRleHQgaW4gcmVkLCByb3RhdGVkIC0yMCBkZWdyZWVzLCA4MCUgc2l6ZQp0ZXh0KHggPSB3aGl0ZXNpZGUkVGVtcFtpbmRleEFdLCB5ID0gd2hpdGVzaWRlJEdhc1tpbmRleEFdLAogICAgIGxhYmVscyA9ICJBZnRlciIsIGNvbCA9ICJyZWQiLCBzcnQgPSAtMjAsIGNleCA9IDAuOCkKYGBgCgpVc2luZyB0aGUgbGVnZW5kKCkgZnVuY3Rpb24KVGhlIHZpZGVvIGRlc2NyaWJlZCBhbmQgaWxsdXN0cmF0ZWQgdGhlIHVzZSBvZiB0aGUgbGVnZW5kKCkgZnVuY3Rpb24gdG8gYWRkIGV4cGxhbmF0b3J5IHRleHQgdG8gYSBwbG90LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBmaXJzdCBjcmVhdGUgYSBzY2F0dGVycGxvdCBhbmQgdGhlbiB1c2UgdGhpcyBmdW5jdGlvbiB0byBhZGQgZXhwbGFuYXRvcnkgdGV4dCBmb3IgdGhlIHBvaW50IHNoYXBlcyB0aGF0IGlkZW50aWZ5IHR3byBkaWZmZXJlbnQgZGF0YSBzdWJzZXRzLgoKYGBge3J9CiMgU2V0IHVwIGFuZCBsYWJlbCBlbXB0eSBwbG90IG9mIEdhcyB2cy4gVGVtcApwbG90KHdoaXRlc2lkZSRUZW1wLCB3aGl0ZXNpZGUkR2FzLAogICAgIHR5cGUgPSAibiIsIHhsYWIgPSAiT3V0c2lkZSB0ZW1wZXJhdHVyZSIsCiAgICAgeWxhYiA9ICJIZWF0aW5nIGdhcyBjb25zdW1wdGlvbiIpCgojIENyZWF0ZSBpbmRleEIsIHBvaW50aW5nIHRvICJCZWZvcmUiIGRhdGEKaW5kZXhCIDwtIHdoaWNoKHdoaXRlc2lkZSRJbnN1bCA9PSAiQmVmb3JlIikKCiMgQ3JlYXRlIGluZGV4QSwgcG9pbnRpbmcgdG8gIkFmdGVyIiBkYXRhCmluZGV4QSA8LSB3aGljaCh3aGl0ZXNpZGUkSW5zdWwgPT0gIkFmdGVyIikKCiMgQWRkICJCZWZvcmUiIGRhdGEgYXMgc29saWQgdHJpYW5nbGVzCnBvaW50cyh3aGl0ZXNpZGUkVGVtcFtpbmRleEJdLCB3aGl0ZXNpZGUkR2FzW2luZGV4Ql0sIHBjaD0xNykKCiMgQWRkICJBZnRlciIgZGF0YSBhcyBvcGVuIGNpcmNsZXMKcG9pbnRzKHdoaXRlc2lkZSRUZW1wW2luZGV4QV0sIHdoaXRlc2lkZSRHYXNbaW5kZXhBXSwgcGNoPTEpCgojIEFkZCBsZWdlbmQgdGhhdCBpZGVudGlmaWVzIHBvaW50cyBhcyAiQmVmb3JlIiBhbmQgIkFmdGVyIgpsZWdlbmQoInRvcHJpZ2h0IiwgcGNoID0gYygxNywxKSwgCiAgICAgICBsZWdlbmQgPSBjKCJCZWZvcmUiLCAiQWZ0ZXIiKSkKYGBgCgpBZGRpbmcgY3VzdG9tIGF4ZXMgd2l0aCB0aGUgYXhpcygpIGZ1bmN0aW9uClR5cGljYWwgYmFzZSBncmFwaGljcyBmdW5jdGlvbnMgbGlrZSBib3hwbG90KCkgcHJvdmlkZSB4LSBhbmQgeS1heGVzIGJ5IGRlZmF1bHQsIHdpdGggYSBsYWJlbCBmb3IgdGhlIHgtYXhpcyBiZWxvdyB0aGUgcGxvdCBhbmQgb25lIGZvciB0aGUgeS1heGlzIGxhYmVsIHRvIHRoZSBsZWZ0IG9mIHRoZSBwbG90LiBUaGVzZSBsYWJlbHMgYXJlIGdlbmVyYXRlZCBhdXRvbWF0aWNhbGx5IGZyb20gdGhlIHZhcmlhYmxlIG5hbWVzIHVzZWQgdG8gZ2VuZXJhdGUgdGhlIHBsb3QuIFNvbWV0aW1lcywgd2Ugd2FudCB0byBwcm92aWRlIG91ciBvd24gYXhlcyBsYWJlbHMsIGFuZCBSIG1ha2VzIHRoaXMgcG9zc2libGUgaW4gdHdvIHN0ZXBzOiBmaXJzdCwgd2Ugc3VwcHJlc3MgdGhlIGRlZmF1bHQgYXhlcyB3aGVuIHdlIGNyZWF0ZSB0aGUgcGxvdCBieSBzcGVjaWZ5aW5nIGF4ZXMgPSBGQUxTRTsgdGhlbiwgd2UgY2FsbCB0aGUgbG93LWxldmVsIGdyYXBoaWNzIGZ1bmN0aW9uIGF4aXMoKSB0byBjcmVhdGUgdGhlIGF4ZXMgd2Ugd2FudC4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdyZSBhc2tlZCB0byBjcmVhdGUgeW91ciBvd24gbGFiZWxzIHVzaW5nIHRoZSBheGlzKCkgZnVuY3Rpb24gd2l0aCB0aGUgc2lkZSwgYXQsIGFuZCBsYWJlbHMgYXJndW1lbnRzLiBUaGUgc2lkZSBhcmd1bWVudCB0ZWxscyB0aGUgZnVuY3Rpb24gd2hpY2ggYXhpcyB0byBjcmVhdGU6IGEgdmFsdWUgb2YgMSBhZGRzIGFuIGF4aXMgYmVsb3cgdGhlIHBsb3Q7IDIgYWRkcyBhbiBheGlzIG9uIHRoZSBsZWZ0OyAzIHB1dHMgaXQgYWNyb3NzIHRoZSB0b3A7IGFuZCA0IHB1dHMgaXQgb24gdGhlIHJpZ2h0IHNpZGUuIFRoZSBzZWNvbmQgYXJndW1lbnQsIGF0LCBpcyBhIHZlY3RvciB0aGF0IGRlZmluZXMgcG9pbnRzIHdoZXJlIHRpY2stbWFya3Mgd2lsbCBiZSBkcmF3biBvbiB0aGUgYXhpcy4gVGhlIHRoaXJkIGFyZ3VtZW50LCBsYWJlbHMsIGlzIGEgdmVjdG9yIHRoYXQgZGVmaW5lcyBsYWJlbHMgYXQgZWFjaCBvZiB0aGVzZSB0aWNrLW1hcmtzLgoKT25lIGV4YW1wbGUgb2YgYSBib3hwbG90IHdpdGggY3VzdG9tIGF4ZXMgd2FzIHByZXNlbnRlZCBpbiB0aGUgdmlkZW8uIFRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGFub3RoZXIgZXhhbXBsZSBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgc3VnYXJzIHZhcmlhYmxlIGFuZCB0aGUgc2hlbGYgdmFyaWFibGUgZnJvbSB0aGUgVVNjZXJlYWwgZGF0YSBmcmFtZSBpbiB0aGUgTUFTUyBwYWNrYWdlLgoKYGBge3J9CiMgQ3JlYXRlIGEgYm94cGxvdCBvZiBzdWdhcnMgYnkgc2hlbGYgdmFsdWUsIHdpdGhvdXQgYXhlcwpib3hwbG90KHN1Z2FycyB+IHNoZWxmLCBkYXRhID0gVVNjZXJlYWwsCiAgICAgICAgYXhlcyA9IEZBTFNFKQoKIyBBZGQgYSBkZWZhdWx0IHktYXhpcyB0byB0aGUgbGVmdCBvZiB0aGUgYm94cGxvdApheGlzKHNpZGUgPSAyKQoKIyBBZGQgYW4geC1heGlzIGJlbG93IHRoZSBwbG90LCBsYWJlbGxlZCAxLCAyLCBhbmQgMwpheGlzKHNpZGUgPSAxLCBhdCA9IGMoMSwgMiwgMykpCgojIEFkZCBhIHNlY29uZCB4LWF4aXMgYWJvdmUgdGhlIHBsb3QKYXhpcyhzaWRlID0gMywgYXQgPSBjKDEsIDIsIDMpLAogICAgIGxhYmVscyA9IGMoImZsb29yIiwgIm1pZGRsZSIsICJ0b3AiKSkKYGBgCgpVc2luZyB0aGUgc3Vwc211KCkgZnVuY3Rpb24gdG8gYWRkIHNtb290aCB0cmVuZCBjdXJ2ZXMKQXMgd2Ugc2F3IGluIHRoZSB2aWRlbywgc29tZSBzY2F0dGVycGxvdHMgZXhoaWJpdCBmYWlybHkgb2J2aW91cyB0cmVuZHMgdGhhdCBhcmUgbm90IGxpbmVhci4gSW4gc3VjaCBjYXNlcywgd2UgbWF5IHdhbnQgdG8gYWRkIGEgY3VydmVkIHRyZW5kIGxpbmUgdGhhdCBoaWdobGlnaHRzIHRoaXMgYmVoYXZpb3Igb2YgdGhlIGRhdGEgYW5kIHRoZSBzdXBzbXUoKSBmdW5jdGlvbiByZXByZXNlbnRzIG9uZSB3YXkgb2YgZG9pbmcgdGhpcy4KClRvIHVzZSB0aGlzIGZ1bmN0aW9uLCB3ZSBuZWVkIHRvIHNwZWNpZnkgdmFsdWVzIGZvciB0aGUgcmVxdWlyZWQgYXJndW1lbnRzIHggYW5kIHksIGJ1dCBpdCBhbHNvIGhhcyBhIG51bWJlciBvZiBvcHRpb25hbCBhcmd1bWVudHMuIEhlcmUsIHdlIGNvbnNpZGVyIHRoZSBvcHRpb25hbCBiYXNzIGFyZ3VtZW50LCB3aGljaCBjb250cm9scyB0aGUgZGVncmVlIG9mIHNtb290aG5lc3MgaW4gdGhlIHJlc3VsdGluZyB0cmVuZCBjdXJ2ZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgMCwgYnV0IHNwZWNpZnlpbmcgbGFyZ2VyIHZhbHVlcyAodXAgdG8gYSBtYXhpbXVtIG9mIDEwKSByZXN1bHRzIGluIGEgc21vb3RoZXIgY3VydmUuIFRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gdXNlIHRoZSBzdXBzbXUoKSBmdW5jdGlvbiB0byBhZGQgdHdvIHRyZW5kIGxpbmVzIHRvIGEgc2NhdHRlcnBsb3QsIG9uZSB1c2luZyB0aGUgZGVmYXVsdCBwYXJhbWV0ZXJzIGFuZCB0aGUgb3RoZXIgd2l0aCBpbmNyZWFzZWQgc21vb3RobmVzcy4KCmBgYHtyfQojIENyZWF0ZSBhIHNjYXR0ZXJwbG90IG9mIE1QRy5jaXR5IHZzLiBIb3JzZXBvd2VyCnBsb3QoQ2FyczkzJEhvcnNlcG93ZXIsIENhcnM5MyRNUEcuY2l0eSkKCiMgQ2FsbCBzdXBzbXUoKSB0byBnZW5lcmF0ZSBhIHNtb290aCB0cmVuZCBjdXJ2ZSwgd2l0aCBkZWZhdWx0IGJhc3MKdHJlbmQxIDwtIHN1cHNtdShDYXJzOTMkSG9yc2Vwb3dlciwgQ2FyczkzJE1QRy5jaXR5KQoKIyBBZGQgdGhpcyB0cmVuZCBjdXJ2ZSB0byB0aGUgcGxvdApsaW5lcyh0cmVuZDEpCgojIENhbGwgc3Vwc211KCkgZm9yIGEgc2Vjb25kIHRyZW5kIGN1cnZlLCB3aXRoIGJhc3MgPSAxMAp0cmVuZDIgPC0gc3Vwc211KENhcnM5MyRIb3JzZXBvd2VyLCBDYXJzOTMkTVBHLmNpdHksIGJhc3MgPTEwKQoKIyBBZGQgdGhpcyB0cmVuZCBjdXJ2ZSBhcyBhIGhlYXZ5LCBkb3R0ZWQgbGluZQpsaW5lcyh0cmVuZDIsIGx0eSA9IDMsIGx3ZCA9IDIpCmBgYAoKVG9vIG11Y2ggaXMgdG9vIG11Y2gKVGhlIGZpcnN0IGV4YW1wbGUgcHJlc2VudGVkIGluIENoYXB0ZXIgMSBhcHBsaWVkIHRoZSBwbG90KCkgZnVuY3Rpb24gdG8gYSBkYXRhIGZyYW1lLCB5aWVsZGluZyBhbiBhcnJheSBvZiBzY2F0dGVycGxvdHMgd2l0aCBvbmUgZm9yIGVhY2ggcGFpciBvZiBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lLiBUaHVzLCB0aGUgbnVtYmVyIG9mIHBsb3RzIGluIHRoaXMgYXJyYXkgaXMgZXF1YWwgdG8gdGhlIHNxdWFyZSBvZiB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgaW4gdGhlIGRhdGEgZnJhbWUuCgpUaGlzIG1lYW5zIHRoYXQgaWYgd2UgYXBwbHkgdGhlIHBsb3QoKSBmdW5jdGlvbiB0byBhIGRhdGEgZnJhbWUgd2l0aCBtYW55IGNvbHVtbnMsIHdlIHdpbGwgZ2VuZXJhdGUgYW4gZW5vcm1vdXMgYXJyYXkgb2Ygc2NhdHRlcnBsb3RzLCBlYWNoIG9mIHdoaWNoIHdpbGwgYmUgdG9vIHNtYWxsIHRvIGJlIHVzZWZ1bC4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBleGVyY2lzZSBpcyB0byBwcm92aWRlIGEgbWVtb3JhYmxlIGV4YW1wbGUuCgpgYGB7cn0KIyBDb21wdXRlIHRoZSBudW1iZXIgb2YgcGxvdHMgdG8gYmUgZGlzcGxheWVkCm5jb2woQ2FyczkzKV4yCgojIFBsb3QgdGhlIGFycmF5IG9mIHNjYXR0ZXJwbG90cwpwbG90KENhcnM5MykKYGBgCgpEZWNpZGluZyBob3cgbWFueSBzY2F0dGVycGxvdHMgaXMgdG9vIG1hbnkKQXMgbm90ZWQgaW4gdGhlIHZpZGVvLCB0aGUgbWF0cGxvdCgpIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIHRvIGVhc2lseSBnZW5lcmF0ZSBhIHBsb3Qgd2l0aCBzZXZlcmFsIHNjYXR0ZXJwbG90cyBvbiB0aGUgc2FtZSBzZXQgb2YgYXhlcy4gQnkgZGVmYXVsdCwgdGhlIHBvaW50cyBpbiB0aGVzZSBzY2F0dGVycGxvdHMgYXJlIHJlcHJlc2VudGVkIGJ5IHRoZSBudW1iZXJzIDEgdGhyb3VnaCBuLCB3aGVyZSBuIGlzIHRoZSB0b3RhbCBudW1iZXIgb2Ygc2NhdHRlcnBsb3RzIGluY2x1ZGVkLCBidXQgbW9zdCBvZiB0aGUgb3B0aW9ucyBhdmFpbGFibGUgd2l0aCB0aGUgcGxvdCgpIGZ1bmN0aW9uIGFyZSBhbHNvIHBvc3NpYmxlIGJ5IHNwZWNpZnlpbmcgdGhlIGFwcHJvcHJpYXRlIGFyZ3VtZW50cy4KClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gc2V0IHVwIGEgcGxvdCBhcnJheSB3aXRoIGZvdXIgb2YgdGhlc2UgbXVsdGlwbGUgc2NhdHRlcnBsb3QgZGlzcGxheXMsIGVhY2ggaW5jbHVkaW5nIG9uZSBtb3JlIHNjYXR0ZXJwbG90IHRoYW4gdGhlIHByZXZpb3VzIG9uZS4gVGhlIHBvaW50IG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZW5jb3VyYWdlIHlvdSB0byBqdWRnZSBmb3IgeW91cnNlbGYgaG93IG1hbnkgc2NhdHRlcnBsb3RzIGlzIHRvbyBtYW55Py4KCmBgYHtyfQojIENvbnN0cnVjdCB0aGUgdmVjdG9yIGtlZXBfdmFycwprZWVwX3ZhcnMgPC0gYygiY2Fsb3JpZXMiLCAicHJvdGVpbiIsICJmYXQiLAogICAgICAgICAgICAgICAiZmlicmUiLCAiY2FyYm8iLCAic3VnYXJzIikKCiMgVXNlIGtlZXBfdmFycyB0byBleHRyYWN0IHRoZSBkZXNpcmVkIHN1YnNldCBvZiBVU2NlcmVhbApkZiA8LSBVU2NlcmVhbFssIGtlZXBfdmFyc10KCiMgU2V0IHVwIGEgdHdvLWJ5LXR3byBwbG90IGFycmF5CnBhcihtZnJvdyA9IGMoMiwyKSkKCiMgVXNlIG1hdHBsb3QoKSB0byBnZW5lcmF0ZSBhbiBhcnJheSBvZiB0d28gc2NhdHRlcnBsb3RzCm1hdHBsb3QoVVNjZXJlYWwkY2Fsb3JpZXMsIFVTY2VyZWFsW2MoInByb3RlaW4iLCAiZmF0IildLCB4bGFiID0gImNhbG9yaWVzIix5bGFiID0gIiIpCgojIEFkZCBhIHRpdGxlCnRpdGxlKCJUd28gc2NhdHRlcnBsb3RzIikKCiMgVXNlIG1hdHBsb3QoKSB0byBnZW5lcmF0ZSBhbiBhcnJheSBvZiB0aHJlZSBzY2F0dGVycGxvdHMKbWF0cGxvdChVU2NlcmVhbCRjYWxvcmllcywgVVNjZXJlYWxbYygicHJvdGVpbiIsICJmYXQiLCAiZmlicmUiKV0sIHhsYWIgPSAiY2Fsb3JpZXMiLHlsYWIgPSAiIikKCiMgQWRkIGEgdGl0bGUKdGl0bGUoIlRocmVlIHNjYXR0ZXJwbG90cyIpCgojIFVzZSBtYXRwbG90KCkgdG8gZ2VuZXJhdGUgYW4gYXJyYXkgb2YgZm91ciBzY2F0dGVycGxvdHMKbWF0cGxvdChVU2NlcmVhbCRjYWxvcmllcywgVVNjZXJlYWxbYygicHJvdGVpbiIsICJmYXQiLCAiZmlicmUiLCAiY2FyYm8iKV0sIHhsYWIgPSAiY2Fsb3JpZXMiLHlsYWIgPSAiIikKCiMgQWRkIGEgdGl0bGUKdGl0bGUoIkZvdXIgc2NhdHRlcnBsb3RzIikKCiMgVXNlIG1hdHBsb3QoKSB0byBnZW5lcmF0ZSBhbiBhcnJheSBvZiBmaXZlIHNjYXR0ZXJwbG90cwptYXRwbG90KFVTY2VyZWFsJGNhbG9yaWVzLCBVU2NlcmVhbFtjKCJwcm90ZWluIiwgImZhdCIsICJmaWJyZSIsICJjYXJibyIsICJzdWdhcnMiKV0sIHhsYWIgPSAiY2Fsb3JpZXMiLHlsYWIgPSAiIikKCiMgQWRkIGEgdGl0bGUKdGl0bGUoIkZpdmUgc2NhdHRlcnBsb3RzIikKYGBgCgpIb3cgbWFueSB3b3JkcyBpcyB0b28gbWFueT8KVGhlIG1haW4gcG9pbnQgb2YgdGhlIHByZXZpb3VzIHR3byBleGVyY2lzZXMgaGFzIGJlZW4gdG8gc2hvdyB0aGF0IHNjYXR0ZXJwbG90IGFycmF5cyBsb3NlIHRoZWlyIHV0aWxpdHkgaWYgdGhleSBhcmUgYWxsb3dlZCB0byBiZWNvbWUgdG9vIGNvbXBsZXgsIGVpdGhlciBpbmNsdWRpbmcgdG9vIG1hbnkgcGxvdHMsIG9yIGF0dGVtcHRpbmcgdG8gaW5jbHVkZSB0b28gbWFueSBzY2F0dGVycGxvdHMgb24gb25lIHNldCBvZiBheGVzLiBNb3JlIGdlbmVyYWxseSwgYW55IGRhdGEgdmlzdWFsaXphdGlvbiBsb3NlcyBpdHMgdXRpbGl0eSBpZiBpdCBiZWNvbWVzIHRvbyBjb21wbGV4LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjb25zaWRlciB0aGlzIHByb2JsZW0gd2l0aCB3b3JkY2xvdWRzLCBkaXNwbGF5cyB0aGF0IHByZXNlbnQgd29yZHMgaW4gdmFyeWluZyBzaXplcyBkZXBlbmRpbmcgb24gdGhlaXIgZnJlcXVlbmN5LiBUaGF0IGlzLCBtb3JlIGZyZXF1ZW50IHdvcmRzIGFwcGVhciBsYXJnZXIgaW4gdGhlIGRpc3BsYXksIHdoaWxlIHJhcmVyIHdvcmRzIGFwcGVhciBpbiBhIHNtYWxsZXIgZm9udC4KCkluIFIsIHdvcmRjbG91ZHMgYXJlIGVhc3kgdG8gZ2VuZXJhdGUgd2l0aCB0aGUgd29yZGNsb3VkKCkgZnVuY3Rpb24gaW4gdGhlIHdvcmRjbG91ZCBwYWNrYWdlLiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGEgY2hhcmFjdGVyIHZlY3RvciBvZiB3b3JkcywgYW5kIGEgc2Vjb25kIG51bWVyaWNhbCB2ZWN0b3IgZ2l2aW5nIHRoZSBudW1iZXIgb2YgdGltZXMgZWFjaCB3b3JkIGFwcGVhcnMgaW4gdGhlIGNvbGxlY3Rpb24gdXNlZCB0byBnZW5lcmF0ZSB0aGUgd29yZGNsb3VkLgoKVHdvIG90aGVyIHVzZWZ1bCBhcmd1bWVudHMgZm9yIHRoaXMgZnVuY3Rpb24gYXJlIHNjYWxlIGFuZCBtaW4uZnJlcS4gVGhlIHNjYWxlIGFyZ3VtZW50IGlzIGEgdHdvLWNvbXBvbmVudCBudW1lcmljYWwgdmVjdG9yIGdpdmluZyB0aGUgcmVsYXRpdmUgc2l6ZSBvZiB0aGUgbGFyZ2VzdCB3b3JkIGluIHRoZSBkaXNwbGF5IGFuZCB0aGF0IG9mIHRoZSBzbWFsbGVzdCB3b3JkLiBUaGUgd29yZGNsb3VkIG9ubHkgaW5jbHVkZXMgdGhvc2Ugd29yZHMgdGhhdCBvY2N1ciBhdCBsZWFzdCBtaW4uZnJlcSB0aW1lcyBpbiB0aGUgY29sbGVjdGlvbiBhbmQgdGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoaXMgYXJndW1lbnQgaXMgMy4KCmBgYHtyfQpsaWJyYXJ5KHdvcmRjbG91ZCkKIyBDcmVhdGUgbWZyX3RhYmxlIG9mIG1hbnVmYWN0dXJlciBmcmVxdWVuY2llcwptZnJfdGFibGUgPC0gdGFibGUoQ2FyczkzJE1hbnVmYWN0dXJlcikKCiMgQ3JlYXRlIHRoZSBkZWZhdWx0IHdvcmRjbG91ZCBmcm9tIHRoaXMgdGFibGUKd29yZGNsb3VkKHdvcmRzID0gbmFtZXMobWZyX3RhYmxlKSwgCiAgICAgICAgICBmcmVxID0gYXMubnVtZXJpYyhtZnJfdGFibGUpLCAKICAgICAgICAgIHNjYWxlID0gYygyLCAwLjI1KSkKCiMgQ2hhbmdlIHRoZSBtaW5pbXVtIHdvcmQgZnJlcXVlbmN5CndvcmRjbG91ZCh3b3JkcyA9IG5hbWVzKG1mcl90YWJsZSksIAogICAgICAgICAgZnJlcSA9IGFzLm51bWVyaWMobWZyX3RhYmxlKSwgCiAgICAgICAgICBzY2FsZSA9IGMoMiwgMC4yNSksIAogICAgICAgICAgbWluLmZyZXEgPSAxKQoKIyBDcmVhdGUgbW9kZWxfdGFibGUgb2YgbW9kZWwgZnJlcXVlbmNpZXMKbW9kZWxfdGFibGUgPC0gdGFibGUoQ2FyczkzJE1vZGVsKQoKIyBDcmVhdGUgdGhlIHdvcmRjbG91ZCBvZiBhbGwgbW9kZWwgbmFtZXMgd2l0aCBzbWFsbGVyIHNjYWxpbmcKd29yZGNsb3VkKHdvcmRzID0gbmFtZXMobW9kZWxfdGFibGUpLCAKICAgICAgICAgIGZyZXEgPSBhcy5udW1lcmljKG1vZGVsX3RhYmxlKSwgCiAgICAgICAgICBzY2FsZSA9IGMoMC43NSwgMC4yNSksIAogICAgICAgICAgbWluLmZyZXEgPSAxKQpgYGAKClRoZSBBbnNjb21iZSBxdWFydGV0ClRoaXMgZXhlcmNpc2UgYW5kIHRoZSBuZXh0IG9uZSBhcmUgYmFzZWQgb24gdGhlIEFuc2NvbWJlIHF1YXJ0ZXQsIGEgY29sbGVjdGlvbiBvZiBmb3VyIGRhdGFzZXRzIHRoYXQgYXBwZWFyIHRvIGJlIGVzc2VudGlhbGx5IGlkZW50aWNhbCBvbiB0aGUgYmFzaXMgb2Ygc2ltcGxlIHN1bW1hcnkgc3RhdGlzdGljcyBsaWtlIG1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zLiBGb3IgZXhhbXBsZSwgdGhlIG1lYW4geC12YWx1ZXMgZm9yIHRoZXNlIGRhdGFzZXRzIGFyZSBpZGVudGljYWwgdG8gdGhyZWUgZGlnaXRzLCB3aGlsZSB0aGUgbWVhbiB5LXZhbHVlcyBkaWZmZXIgb25seSBpbiB0aGUgdGhpcmQgZGlnaXQuCgpJbiBzcGl0ZSBvZiB0aGVzZSBhcHBhcmVudCBzaW1pbGFyaXRpZXMsIHRoZSBiZWhhdmlvciBvZiB0aGUgZm91ciBkYXRhc2V0cyBpcyBxdWl0ZSBkaWZmZXJlbnQgYW5kIHRoaXMgYmVjb21lcyBpbW1lZGlhdGVseSBhcHBhcmVudCB3aGVuIHdlIHBsb3QgdGhlbS4KCmBgYHtyfQojIFNldCB1cCBhIHR3by1ieS10d28gcGxvdCBhcnJheQpwYXIobWZyb3cgPSBjKDIsMikpCgojIFBsb3QgeTEgdnMuIHgxIApwbG90KGFuc2NvbWJlJHgxLCBhbnNjb21iZSR5MSkKCiMgUGxvdCB5MiB2cy4geDIKcGxvdChhbnNjb21iZSR4MiwgYW5zY29tYmUkeTIpCgojIFBsb3QgeTMgdnMuIHgzCnBsb3QoYW5zY29tYmUkeDMsIGFuc2NvbWJlJHkzKQoKIyBQbG90IHk0IHZzLiB4NApwbG90KGFuc2NvbWJlJHg0LCBhbnNjb21iZSR5NCkKYGBgCgpUaGUgdXRpbGl0eSBvZiBjb21tb24gc2NhbGluZyBhbmQgaW5kaXZpZHVhbCB0aXRsZXMKVGhlIHBsb3RzIHlvdSBnZW5lcmF0ZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHNob3dlZCB0aGF0IHRoZSBmb3VyIEFuc2NvbWJlIHF1YXJ0ZXQgZGF0YXNldHMgaGF2ZSB2ZXJ5IGRpZmZlcmVudCBhcHBlYXJhbmNlcywgYnV0IGEgY2FyZWZ1bCBleGFtaW5hdGlvbiBvZiB0aGVzZSBwbG90cyByZXZlYWxzIHRoYXQgdGhleSBleGhpYml0IGRpZmZlcmVudCByYW5nZXMgb2YgeCBhbmQgeSB2YWx1ZXMuCgpUaGUgcG9pbnQgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBpbGx1c3RyYXRlIGhvdyBtdWNoIG1vcmUgY2xlYXJseSB3ZSBjYW4gc2VlIHRoZSBkaWZmZXJlbmNlcyBpbiB0aGVzZSBkYXRhc2V0cyBpZiB3ZSBwbG90IGFsbCBvZiB0aGVtIHdpdGggdGhlIHNhbWUgeCBhbmQgeSByYW5nZXMuIFRoaXMgZXhlcmNpc2UgYWxzbyBpbGx1c3RyYXRlcyB0aGUgdXRpbGl0eSBvZiBpbXByb3ZpbmcgdGhlIHgtIGFuZCB5LWF4aXMgbGFiZWxzIGFuZCBvZiBhZGRpbmcgaW5mb3JtYXRpdmUgcGxvdCB0aXRsZXMuCgpgYGB7cn0KIyBEZWZpbmUgY29tbW9uIHggYW5kIHkgbGltaXRzIGZvciB0aGUgZm91ciBwbG90cwp4bWluIDwtIDQKeG1heCA8LSAxOQp5bWluIDwtIDMKeW1heCA8LSAxMwoKIyBTZXQgdXAgYSB0d28tYnktdHdvIHBsb3QgYXJyYXkKcGFyKG1mcm93ID0gYygyLDIpKQoKIyBQbG90IHkxIHZzLiB4MSB3aXRoIGNvbW1vbiB4IGFuZCB5IGxpbWl0cywgbGFiZWxzICYgdGl0bGUKcGxvdChhbnNjb21iZSR4MSwgYW5zY29tYmUkeTEsCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gIkZpcnN0IGRhdGFzZXQiKQoKIyBEbyB0aGUgc2FtZSBmb3IgdGhlIHkyIHZzLiB4MiBwbG90CnBsb3QoYW5zY29tYmUkeDIsIGFuc2NvbWJlJHkyLAogICAgIHhsaW0gPSBjKHhtaW4sIHhtYXgpLAogICAgIHlsaW0gPSBjKHltaW4sIHltYXgpLAogICAgIHhsYWIgPSAieCB2YWx1ZSIsIHlsYWIgPSAieSB2YWx1ZSIsCiAgICAgbWFpbiA9ICJTZWNvbmQgZGF0YXNldCIpCgojIERvIHRoZSBzYW1lIGZvciB0aGUgeTMgdnMuIHgzIHBsb3QKcGxvdChhbnNjb21iZSR4MywgYW5zY29tYmUkeTMsCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gIlRoaXJkIGRhdGFzZXQiKQoKIyBEbyB0aGUgc2FtZSBmb3IgdGhlIHk0IHZzLiB4NCBwbG90CnBsb3QoYW5zY29tYmUkeDQsIGFuc2NvbWJlJHk0LAogICAgIHhsaW0gPSBjKHhtaW4sIHhtYXgpLAogICAgIHlsaW0gPSBjKHltaW4sIHltYXgpLAogICAgIHhsYWIgPSAieCB2YWx1ZSIsIHlsYWIgPSAieSB2YWx1ZSIsCiAgICAgbWFpbiA9ICJGb3VydGggZGF0YXNldCIpCmBgYAoKVXNpbmcgbXVsdGlwbGUgcGxvdHMgdG8gZ2l2ZSBtdWx0aXBsZSB2aWV3cyBvZiBhIGRhdGFzZXQKQXMgbm90ZWQgaW4gdGhlIHZpZGVvLCBhbm90aGVyIHVzZWZ1bCBhcHBsaWNhdGlvbiBvZiBtdWx0aXBsZSBwbG90IGFycmF5cyBiZXNpZGVzIGNvbXBhcmlzb24gaXMgcHJlc2VudGluZyBtdWx0aXBsZSByZWxhdGVkIHZpZXdzIG9mIHRoZSBzYW1lIGRhdGFzZXQuCgpUaGlzIGV4ZXJjaXNlIGlsbHVzdHJhdGVzIHRoaXMgaWRlYSwgZ2l2aW5nIGZvdXIgdmlld3Mgb2YgdGhlIHNhbWUgZGF0YXNldDogYSBwbG90IG9mIHRoZSByYXcgZGF0YSB2YWx1ZXMgdGhlbXNlbHZlcywgYSBoaXN0b2dyYW0gb2YgdGhlc2UgZGF0YSB2YWx1ZXMsIGEgZGVuc2l0eSBwbG90LCBhbmQgYSBub3JtYWwgUVEtcGxvdC4KCmBgYHtyfQojIFNldCB1cCBhIHR3by1ieS10d28gcGxvdCBhcnJheQpwYXIobWZyb3cgPSBjKDIsMikpCgojIFBsb3QgdGhlIHJhdyBkdXJhdGlvbiBkYXRhCnBsb3QoZ2V5c2VyJGR1cmF0aW9uLCBtYWluID0gIlJhdyBkYXRhIikKCiMgUGxvdCB0aGUgbm9ybWFsaXplZCBoaXN0b2dyYW0gb2YgdGhlIGR1cmF0aW9uIGRhdGEKdHJ1ZWhpc3QoZ2V5c2VyJGR1cmF0aW9uLCBtYWluID0gIkhpc3RvZ3JhbSIpCgojIFBsb3QgdGhlIGRlbnNpdHkgb2YgdGhlIGR1cmF0aW9uIGRhdGEKcGxvdChkZW5zaXR5KGdleXNlciRkdXJhdGlvbiksIG1haW4gPSAiRGVuc2l0eSIpCgojIENvbnN0cnVjdCB0aGUgbm9ybWFsIFFRLXBsb3Qgb2YgdGhlIGR1cmF0aW9uIGRhdGEKcXFQbG90KGdleXNlciRkdXJhdGlvbiwgbWFpbiA9ICJRUS1wbG90IikKYGBgCgpDb25zdHJ1Y3RpbmcgYW5kIGRpc3BsYXlpbmcgbGF5b3V0IG1hdHJpY2VzClRoZSB2aWRlbyBpbGx1c3RyYXRlZCBob3cgdG8gc2V0IHVwIGEgbGF5b3V0IG1hdHJpeCB0byBiZSB1c2VkIHdpdGggdGhlIGxheW91dCgpIGZ1bmN0aW9uIGluIGNyZWF0aW5nIGEgcGxvdCBhcnJheS4gWW91IGNhbiB0aGluayBvZiB0aGUgbGF5b3V0IG1hdHJpeCBhcyB0aGUgcGxvdCBwYW5lLCB3aGVyZSBhIDAgcmVwcmVzZW50cyBlbXB0eSBzcGFjZSBhbmQgb3RoZXIgbnVtYmVycyByZXByZXNlbnQgdGhlIHBsb3QgbnVtYmVyLCB3aGljaCBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBzZXF1ZW5jZSBvZiB2aXN1YWxpemF0aW9uIGZ1bmN0aW9uIGNhbGxzLiBGb3IgZXhhbXBsZSwgYSAxIGluIHRoZSBsYXlvdXQgbWF0cml4IHJlZmVycyB0byB0aGUgdmlzdWFsaXphdGlvbiB0aGF0IHdhcyBmaXJzdCBjYWxsZWQsIGEgMiByZWZlcnMgdG8gdGhlIHBsb3Qgb2YgdGhlIHNlY29uZCB2aXN1YWxpemF0aW9uIGNhbGwsIGV0Yy4gVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjcmVhdGUgeW91ciBvd24gMyB4IDIgbGF5b3V0IG1hdHJpeCwgdXNpbmcgdGhlIGMoKSBmdW5jdGlvbiB0byBjb25jYXRlbmF0ZSBudW1iZXJzIGludG8gdmVjdG9ycyB0aGF0IHdpbGwgZm9ybSB0aGUgcm93cyBvZiB0aGUgbWF0cml4LgoKWW91IHdpbGwgdGhlbiB1c2UgdGhlIG1hdHJpeCgpIGZ1bmN0aW9uIHRvIGNvbnZlcnQgdGhlc2Ugcm93cyBpbnRvIGEgbWF0cml4IGFuZCBhcHBseSB0aGUgbGF5b3V0KCkgZnVuY3Rpb24gdG8gc2V0IHVwIHRoZSBkZXNpcmVkIHBsb3QgYXJyYXkuIFRoZSBjb252ZW5pZW5jZSBmdW5jdGlvbiBsYXlvdXQuc2hvdygpIGNhbiB0aGVuIGJlIHVzZWQgdG8gdmVyaWZ5IHRoYXQgdGhlIHBsb3QgYXJyYXkgaGFzIHRoZSBzaGFwZSB5b3Ugd2FudC4KCkFzIHJlZmVyZW5jZSwgZmVlbCBmcmVlIHRvIHVzZSB0aGUgc2xpZGVzIGZyb20gdGhlIHZpZGVvLCB3aGljaCB5b3UgY2FuIGFjY2VzcyBieSBjbGlja2luZyBvbiB0aGUgIlNsaWRlcyIgdGFiIG5leHQgdG8gdGhlICJSIENvbnNvbGUiIHRhYi4gUGF5IGNsb3NlIGF0dGVudGlvbiB0byB0aGUgZXhhbXBsZSBsYXlvdXQgbWF0cml4IGFuZCB0aGUgcmVzdWx0aW5nIHBsb3QgYXJyYXkuCgpgYGB7cn0KIyBVc2UgdGhlIG1hdHJpeCBmdW5jdGlvbiB0byBjcmVhdGUgYSBtYXRyaXggd2l0aCB0aHJlZSByb3dzIGFuZCB0d28gY29sdW1ucwpsYXlvdXRNYXRyaXggPC0gbWF0cml4KAogIGMoCiAgICAwLCAxLAogICAgMiwgMCwKICAgIDAsIDMKICApLCAKICBieXJvdyA9IFRSVUUsIAogIG5yb3cgPSAzCikKCiMgQ2FsbCB0aGUgbGF5b3V0KCkgZnVuY3Rpb24gdG8gc2V0IHVwIHRoZSBwbG90IGFycmF5CmxheW91dChsYXlvdXRNYXRyaXgpCgojIFNob3cgd2hlcmUgdGhlIHRocmVlIHBsb3RzIHdpbGwgZ28gCmxheW91dC5zaG93KG4gPSAzKQpgYGAKCkNyZWF0aW5nIGEgdHJpYW5ndWxhciBhcnJheSBvZiBwbG90cwpUaGUgcHJldmlvdXMgZXhlcmNpc2UgYXNrZWQgeW91IHRvIGNyZWF0ZSBhIHBsb3QgYXJyYXkgdXNpbmcgdGhlIGxheW91dCgpIGZ1bmN0aW9uLiBSZWNhbGwgdGhlIGxheW91dCBtYXRyaXggZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2U6Cgo+IGxheW91dE1hdHJpeAogICAgIFssMV0gWywyXQpbMSxdICAgIDAgICAgMQpbMixdICAgIDIgICAgMApbMyxdICAgIDAgICAgMwpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIHVzZSB0aGlzIGFycmF5IHRvIGdpdmUgdGhyZWUgZGlmZmVyZW50IHZpZXdzIG9mIHRoZSB3aGl0ZXNpZGUgZGF0YSBmcmFtZS4KClRoZSBmaXJzdCBwbG90LCBvbiB0aGUgdXBwZXIgcmlnaHQgb2YgdGhlIHBsb3QgYXJyYXksIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgb2YgR2FzIGFuZCBUZW1wIHVzaW5nIGFsbCBkYXRhIGZyb20gd2hpdGVzaWRlLiBUaGUgc2Vjb25kIHBsb3QsIGluIHRoZSBjZW50ZXIgbGVmdCBvZiB0aGUgcGxvdCBhcnJheSwgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBvZiB0aGUgdHdvIHZhcmlhYmxlcyB1c2luZyBkYXRhIHdoZXJlIEluc3VsIGlzIGVxdWFsIHRvICJCZWZvcmUiLiBGaW5hbGx5LCB0aGUgdGhpcmQgcGxvdCwgb24gdGhlIGxvd2VyIGxlZnQgb2YgdGhlIHBsb3QgYXJyYXksIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgdXNpbmcgZGF0YSB3aGVyZSBJbnN1bCBpcyBlcXVhbCB0byAiQWZ0ZXIiLgoKVGhlIHByaW1hcnkgbW90aXZhdGlvbiBmb3IgdGhpcyBleGVyY2lzZSBpcyB0aGF0IGl0IGlzIG5vdCBwb3NzaWJsZSB0byBjb25zdHJ1Y3QgYSBwbG90IGFycmF5IGluIHRoaXMgZm9ybWF0IHVzaW5nIHRoZSBtZnJvdyBwYXJhbWV0ZXIsIHNpbmNlIHRoZSBhcnJheSBpcyBub3QgcmVjdGFuZ3VsYXIuCgpgYGB7cn0KIyBTZXQgdXAgdGhlIHBsb3QgYXJyYXkKbGF5b3V0KGxheW91dE1hdHJpeCkKCiMgQ29uc3RydWN0IHZlY3RvcnMgaW5kZXhCIGFuZCBpbmRleEEKaW5kZXhCIDwtIHdoaWNoKHdoaXRlc2lkZSRJbnN1bCA9PSAiQmVmb3JlIikKaW5kZXhBIDwtIHdoaWNoKHdoaXRlc2lkZSRJbnN1bCA9PSAiQWZ0ZXIiKQoKIyBDcmVhdGUgcGxvdCAxIGFuZCBhZGQgdGl0bGUKcGxvdCh3aGl0ZXNpZGUkVGVtcFtpbmRleEJdLCB3aGl0ZXNpZGUkR2FzW2luZGV4Ql0sCiAgICAgeWxpbSA9IGMoMCw4KSkKdGl0bGUoIkJlZm9yZSBkYXRhIG9ubHkiKQoKIyBDcmVhdGUgcGxvdCAyIGFuZCBhZGQgdGl0bGUKcGxvdCh3aGl0ZXNpZGUkVGVtcCwgd2hpdGVzaWRlJEdhcywKICAgICB5bGltID0gYygwLDgpKQp0aXRsZSgiQ29tcGxldGUgZGF0YXNldCIpCgojIENyZWF0ZSBwbG90IDMgYW5kIGFkZCB0aXRsZQpwbG90KHdoaXRlc2lkZSRUZW1wW2luZGV4QV0sIHdoaXRlc2lkZSRHYXNbaW5kZXhBXSwKICAgICB5bGltID0gYygwLDgpKQp0aXRsZSgiQWZ0ZXIgZGF0YSBvbmx5IikKYGBgCgpDcmVhdGluZyBhcnJheXMgd2l0aCBkaWZmZXJlbnQgc2l6ZWQgcGxvdHMKQmVzaWRlcyBjcmVhdGluZyBub24tcmVjdGFuZ3VsYXIgYXJyYXlzLCB0aGUgbGF5b3V0KCkgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gY3JlYXRlIHBsb3QgYXJyYXlzIHdpdGggZGlmZmVyZW50IHNpemVkIGNvbXBvbmVudCBwbG90cyAtLSBzb21ldGhpbmcgZWxzZSB0aGF0IGlzIG5vdCBwb3NzaWJsZSBieSBzZXR0aW5nIHRoZSBwYXIoKSBmdW5jdGlvbidzIG1mcm93IHBhcmFtZXRlci4KClRoaXMgZXhlcmNpc2UgaWxsdXN0cmF0ZXMgdGhlIHBvaW50LCBhc2tpbmcgeW91IHRvIGNyZWF0ZSBhIHN0YW5kYXJkIHNjYXR0ZXJwbG90IG9mIHRoZSB6biB2ZXJzdXMgcmFkIHZhcmlhYmxlcyBmcm9tIHRoZSBCb3N0b24gZGF0YSBmcmFtZSBhcyBhIHNtYWxsZXIgcGxvdCBpbiB0aGUgdXBwZXIgbGVmdCwgd2l0aCBhIGxhcmdlciBzdW5mbG93ZXIgcGxvdCBvZiB0aGUgc2FtZSBkYXRhIGluIHRoZSBsb3dlciByaWdodC4KCmBgYHtyfQojIENyZWF0ZSByb3cxLCByb3cyLCBhbmQgbGF5b3V0VmVjdG9yCnJvdzEgPC0gYygxLCAwLCAwKQpyb3cyIDwtIGMoMCwgMiwgMikKbGF5b3V0VmVjdG9yIDwtIGMocm93MSwgcmVwKHJvdzIsIDIpKQoKIyBDb252ZXJ0IGxheW91dFZlY3RvciBpbnRvIGxheW91dE1hdHJpeApsYXlvdXRNYXRyaXggPC0gbWF0cml4KGxheW91dFZlY3RvciwgYnlyb3cgPSBUUlVFLCBucm93ID0gMykKCiMgU2V0IHVwIHRoZSBwbG90IGFycmF5CmxheW91dChsYXlvdXRNYXRyaXgpCgojIFBsb3Qgc2NhdHRlcnBsb3QKcGxvdChCb3N0b24kcmFkLCBCb3N0b24kem4pCgojIFBsb3Qgc3VuZmxvd2VyIHBsb3QKc3VuZmxvd2VycGxvdChCb3N0b24kcmFkLCBCb3N0b24kem4pCmBgYAoKU29tZSBwbG90IGZ1bmN0aW9ucyBhbHNvIHJldHVybiB1c2VmdWwgaW5mb3JtYXRpb24KQXMgc2hvd24gaW4gdGhlIHZpZGVvLCBjYWxsaW5nIHRoZSBiYXJwbG90KCkgZnVuY3Rpb24gaGFzIHRoZSBzaWRlIGVmZmVjdCBvZiBjcmVhdGluZyB0aGUgcGxvdCB3ZSB3YW50LCBidXQgaXQgYWxzbyByZXR1cm5zIGEgbnVtZXJpY2FsIHZlY3RvciB3aXRoIHRoZSBjZW50ZXIgcG9zaXRpb25zIG9mIGVhY2ggYmFyIGluIHRoZSBwbG90LiBUaGlzIHZhbHVlIGlzIHJldHVybmVkIGludmlzaWJseSBzbyB3ZSBkb24ndCBub3JtYWxseSBzZWUgaXQsIGJ1dCB3ZSBjYW4gY2FwdHVyZSBpdCB3aXRoIGFuIGFzc2lnbm1lbnQgc3RhdGVtZW50LgoKVGhlc2UgcmV0dXJuIHZhbHVlcyBjYW4gYmUgZXNwZWNpYWxseSB1c2VmdWwgd2hlbiB3ZSB3YW50IHRvIG92ZXJsYXkgdGV4dCBvbiB0aGUgYmFycyBvZiBhIGhvcml6b250YWwgYmFycGxvdC4gVGhlbiwgd2UgY2FwdHVyZSB0aGUgcmV0dXJuIHZhbHVlcyBhbmQgdXNlIHRoZW0gYXMgdGhlIHkgcGFyYW1ldGVyIGluIGEgc3Vic2VxdWVudCBjYWxsIHRvIHRoZSB0ZXh0KCkgZnVuY3Rpb24sIGFsbG93aW5nIHVzIHRvIHBsYWNlIHRoZSB0ZXh0IGF0IHdoYXRldmVyIHggcG9zaXRpb24gd2Ugd2FudCBidXQgb3ZlcmxhaWQgaW4gdGhlIG1pZGRsZSBvZiBlYWNoIGhvcml6b250YWwgYmFyLiBUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGNvbnN0cnVjdCBhIGhvcml6b250YWwgYmFycGxvdCB0aGF0IGV4cGxvaXRzIHRoZXNlIHBvc3NpYmlsaXRpZXMuCgpGZWVsIGZyZWUgdG8gcmVmZXJlbmNlIGEgc2ltaWxhciBleGFtcGxlIGluIHRoZSBzbGlkZXMgYnkgY2xpY2tpbmcgb24gdGhlICJTbGlkZXMiIHRhYiBuZXh0IHRvIHRoZSAiUiBDb25zb2xlIiB0YWIuCgpgYGB7cn0KIyBDcmVhdGUgYSB0YWJsZSBvZiBDeWxpbmRlcnMgZnJlcXVlbmNpZXMKdGJsIDwtIHRhYmxlKENhcnM5MyRDeWxpbmRlcnMpCgojIEdlbmVyYXRlIGEgaG9yaXpvbnRhbCBiYXJwbG90IG9mIHRoZXNlIGZyZXF1ZW5jaWVzCm1pZHMgPC0gYmFycGxvdCh0YmwsIGhvcml6ID0gVFJVRSwgCiAgICAgICAgICAgICAgICBjb2wgPSAidHJhbnNwYXJlbnQiLAogICAgICAgICAgICAgICAgbmFtZXMuYXJnID0gIiIpCgojIEFkZCBuYW1lcyBsYWJlbHMgd2l0aCB0ZXh0KCkKdGV4dCgyMCwgbWlkcywgbmFtZXModGJsKSkKCiMgQWRkIGNvdW50IGxhYmVscyB3aXRoIHRleHQoKQp0ZXh0KDM1LCBtaWRzLCBhcy5udW1lcmljKHRibCkpCmBgYAoKVXNpbmcgdGhlIHN5bWJvbHMoKSBmdW5jdGlvbiB0byBkaXNwbGF5IHJlbGF0aW9ucyBiZXR3ZWVuIG1vcmUgdGhhbiB0d28gdmFyaWFibGVzClRoZSBzY2F0dGVycGxvdCBhbGxvd3MgdXMgdG8gc2VlIGhvdyBvbmUgbnVtZXJpY2FsIHZhcmlhYmxlIGNoYW5nZXMgd2l0aCB0aGUgdmFsdWVzIG9mIGEgc2Vjb25kIG51bWVyaWNhbCB2YXJpYWJsZS4gVGhlIHN5bWJvbHMoKSBmdW5jdGlvbiBhbGxvd3MgdXMgdG8gZXh0ZW5kIHNjYXR0ZXJwbG90cyB0byBzaG93IHRoZSBpbmZsdWVuY2Ugb2Ygb3RoZXIgdmFyaWFibGVzLgoKVGhpcyBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCB0aGUgdmFyaWFibGVzIHggYW5kIHkgdGhhdCBkZWZpbmUgYSBzY2F0dGVycGxvdCwgYWxvbmcgd2l0aCBhbm90aGVyIGFyZ3VtZW50IHRoYXQgc3BlY2lmaWVzIG9uZSBvZiBzZXZlcmFsIHBvc3NpYmxlIHNoYXBlcy4gSGVyZSwgeW91IGFyZSBhc2tlZCB0byB1c2UgdGhlIGNpcmNsZXMgYXJndW1lbnQgdG8gY3JlYXRlIGEgYnViYmxlcGxvdCB3aGVyZSBlYWNoIGRhdGEgcG9pbnQgaXMgcmVwcmVzZW50ZWQgYnkgYSBjaXJjbGUgd2hvc2UgcmFkaXVzIGRlcGVuZHMgb24gdGhlIHRoaXJkIHZhcmlhYmxlIHNwZWNpZmllZCBieSB0aGUgdmFsdWUgb2YgdGhpcyBhcmd1bWVudC4KCmBgYHtyfQojIENhbGwgc3ltYm9scygpIHRvIGNyZWF0ZSB0aGUgZGVmYXVsdCBidWJibGVwbG90CnN5bWJvbHMoQ2FyczkzJEhvcnNlcG93ZXIsIENhcnM5MyRNUEcuY2l0eSwKICAgICAgICBjaXJjbGVzID0gc3FydChDYXJzOTMkUHJpY2UpKQoKIyBSZXBlYXQsIHdpdGggdGhlIGluY2hlcyBhcmd1bWVudCBzcGVjaWZpZWQKc3ltYm9scyhDYXJzOTMkSG9yc2Vwb3dlciwgQ2FyczkzJE1QRy5jaXR5LAogICAgICAgIGNpcmNsZXMgPSBzcXJ0KENhcnM5MyRQcmljZSksCiAgICAgICAgaW5jaGVzID0gMC4xKQpgYGAKClNhdmluZyBwbG90IHJlc3VsdHMgYXMgZmlsZXMKSW4gYW4gaW50ZXJhY3RpdmUgUiBzZXNzaW9uLCB3ZSB0eXBpY2FsbHkgZ2VuZXJhdGUgYSBjb2xsZWN0aW9uIG9mIGRpZmZlcmVudCBwbG90cywgb2Z0ZW4gdXNpbmcgdGhlIHJlc3VsdHMgdG8gaGVscCB1cyBkZWNpZGUgaG93IHRvIHByb2NlZWQgd2l0aCBvdXIgYW5hbHlzaXMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHRydWUgaW4gdGhlIGVhcmx5IHBoYXNlcyBvZiBhbiBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzLCBidXQgb25jZSB3ZSBoYXZlIGdlbmVyYXRlZCBhIHBsb3Qgd2Ugd2FudCB0byBzaGFyZSB3aXRoIG90aGVycywgaXQgaXMgaW1wb3J0YW50IHRvIHNhdmUgaXQgaW4gYW4gZXh0ZXJuYWwgZmlsZS4KClIgcHJvdmlkZXMgc3VwcG9ydCBmb3Igc2F2aW5nIGdyYXBoaWNhbCByZXN1bHRzIGluIHNldmVyYWwgZGlmZmVyZW50IGV4dGVybmFsIGZpbGUgZm9ybWF0cywgaW5jbHVkaW5nIGpwZWcsIHBuZywgdGlmZiwgb3IgcGRmIGZpbGVzLiBJbiBhZGRpdGlvbiwgd2UgY2FuIGluY29ycG9yYXRlIGdyYXBoaWNhbCByZXN1bHRzIGludG8gZXh0ZXJuYWwgZG9jdW1lbnRzLCB1c2luZyB0b29scyBsaWtlIHRoZSBTd2VhdmUoKSBmdW5jdGlvbiBvciB0aGUga25pdHIgcGFja2FnZS4gT25lIHBhcnRpY3VsYXJseSBjb252ZW5pZW50IHdheSBvZiBkb2luZyB0aGlzIGlzIHRvIGNyZWF0ZSBhbiBSIE1hcmtkb3duIGRvY3VtZW50LCBhbiBhcHByb2FjaCB0aGF0IGZvcm1zIHRoZSBiYXNpcyBmb3IgYW5vdGhlciBEYXRhQ2FtcCBjb3Vyc2UuCgpCZWNhdXNlIHBuZyBmaWxlcyBjYW4gYmUgZWFzaWx5IHNoYXJlZCBhbmQgdmlld2VkIGFzIGUtbWFpbCBhdHRhY2htZW50cyBhbmQgaW5jb3Jwb3JhdGVkIGludG8gbWFueSBzbGlkZSBwcmVwYXJhdGlvbiBwYWNrYWdlcyAoZS5nLiBNaWNyb3NvZnQgUG93ZXJwb2ludCksIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGEgcGxvdCBhbmQgc2F2ZSBpdCBhcyBhIHBuZyBmaWxlLiBUaGUgYmFzaXMgZm9yIHRoaXMgcHJvY2VzcyBpcyB0aGUgcG5nKCkgZnVuY3Rpb24sIHdoaWNoIHNwZWNpZmllcyB0aGUgbmFtZSBvZiB0aGUgcG5nIGZpbGUgdG8gYmUgZ2VuZXJhdGVkIGFuZCBzZXRzIHVwIGEgc3BlY2lhbCBlbnZpcm9ubWVudCB0aGF0IGNhcHR1cmVzIGFsbCBncmFwaGljYWwgb3V0cHV0IHVudGlsIHdlIGV4aXQgdGhpcyBlbnZpcm9ubWVudCB3aXRoIHRoZSBkZXYub2ZmKCkgY29tbWFuZC4KCmBgYHtyfQojIENhbGwgcG5nKCkgd2l0aCB0aGUgbmFtZSBvZiB0aGUgZmlsZSB3ZSB3YW50IHRvIGNyZWF0ZQpwbmcoImJ1YmJsZXBsb3QucG5nIikKCiMgUmUtY3JlYXRlIHRoZSBwbG90IGZyb20gdGhlIGxhc3QgZXhlcmNpc2UKc3ltYm9scyhDYXJzOTMkSG9yc2Vwb3dlciwgQ2FyczkzJE1QRy5jaXR5LAogICAgICAgIGNpcmNsZXMgPSBzcXJ0KENhcnM5MyRQcmljZSksCiAgICAgICAgaW5jaGVzID0gMC4xKQoKIyBTYXZlIG91ciBmaWxlIGFuZCByZXR1cm4gdG8gb3VyIGludGVyYWN0aXZlIHNlc3Npb24KZGV2Lm9mZigpCgojIFZlcmlmeSB0aGF0IHdlIGhhdmUgY3JlYXRlZCB0aGUgZmlsZQpsaXN0LmZpbGVzKHBhdHRlcm4gPSAicG5nIikKYGBgCgpJbGlpbnNreSBhbmQgU3RlZWxlJ3MgMTIgcmVjb21tZW5kZWQgY29sb3JzClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGEgaG9yaXpvbnRhbCBiYXJwbG90IHRoYXQgc2hvd3MgSWxpaW5za3kgYW5kIFN0ZWVsZSdzIHNldCBvZiByZWNvbW1lbmRlZCAxMiBjb2xvcnMsIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgZGVzaXJhYmlsaXR5IGZyb20gdGhlIHRvcCBvZiB0aGUgcGxvdCB0byB0aGUgYm90dG9tLiBBbHNvLCB0aGUgZmlyc3Qgc2l4ICJtb3JlIHByZWZlcnJlZCIgY29sb3JzIGFyZSBkaXNwbGF5ZWQgd2l0aCBsb25nZXIgYmFycyB0byB2aXN1YWxseSBlbXBoYXNpemUgdGhlaXIgcHJlZmVycmVkIHN0YXR1cyBvdmVyIHRoZSBvdGhlciBzaXguCgpDb2RlIGlzIHByb3ZpZGVkIHRvIGNyZWF0ZSB0aGUgY2hhcmFjdGVyIHZlY3RvciBJU2NvbG9ycyB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgMTIgY29sb3JzIHJlY29tbWVuZGVkIGJ5IElsaWluc2t5IGFuZCBTdGVlbGUsIGluIHRoZWlyIHJlY29tbWVuZGVkIG9yZGVyLiBXZSd2ZSBhbHNvIGNyZWF0ZWQgdGhlIG51bWVyaWMgdmVjdG9yIGJhcldpZHRocyBjb250YWluaW5nIHRoZSB2YWx1ZSAyIGZvciB0aGUgZmlyc3Qgc2l4IElsaWluc2t5IGFuZCBTdGVlbGUgY29sb3JzIGFuZCB0aGUgdmFsdWUgMSBmb3IgdGhlIG5leHQgc2l4LgoKSW4gdGhpcyBleGVyY2lzZSwgeW91J2xsIHVzZSB0aGUgYmFycGxvdCgpIGZ1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgaG9yaXpvbnRhbCBiYXJwbG90IHNob3duIGluIHRoZSBwcmVjZWVkaW5nIGZpZ3VyZSwgd2l0aCB0aGUgY29sb3IgbmFtZXMgdG8gdGhlIGxlZnQgb2YgdGhlIGJhcnMgYW5kIGVhY2ggYmFyIGRyYXduIGluIHRoZSBpbmRpY2F0ZWQgY29sb3IuCgpgYGB7cn0KIyBJbGlpbnNreSBhbmQgU3RlZWxlIGNvbG9yIG5hbWUgdmVjdG9yCklTY29sb3JzIDwtIGMoInJlZCIsICJncmVlbiIsICJ5ZWxsb3ciLCAiYmx1ZSIsCiAgICAgICAgICAgICAgImJsYWNrIiwgIndoaXRlIiwgInBpbmsiLCAiY3lhbiIsCiAgICAgICAgICAgICAgImdyYXkiLCAib3JhbmdlIiwgImJyb3duIiwgInB1cnBsZSIpCgojIENyZWF0ZSB0aGUgZGF0YSBmb3IgdGhlIGJhcnBsb3QKYmFyV2lkdGhzIDwtIGMocmVwKDIsIDYpLCByZXAoMSwgNikpCgojIFJlY3JlYXRlIHRoZSBob3Jpem9udGFsIGJhcnBsb3Qgd2l0aCBjb2xvcmVkIGJhcnMKYmFycGxvdChyZXYoYmFyV2lkdGhzKSwgaG9yaXogPSBUUlVFLAogICAgICAgIGNvbCA9IHJldihJU2NvbG9ycyksIGF4ZXMgPSBGLAogICAgICAgIG5hbWVzLmFyZyA9IHJldihJU2NvbG9ycyksIGxhcyA9IDEpCmBgYAoKVXNpbmcgY29sb3IgdG8gZW5oYW5jZSBhIGJ1YmJsZXBsb3QKSW4gYSBwcmV2aW91cyBleGVyY2lzZSwgeW91IHNhdyBob3cgdGhlIHN5bWJvbHMoKSBmdW5jdGlvbiBjb3VsZCBiZSB1c2VkIHRvIGdlbmVyYXRlIGEgYnViYmxlcGxvdCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aHJlZSB2YXJpYWJsZXMgKHNwZWNpZmljYWxseSwgSG9yc2Vwb3dlciwgTVBHLmNpdHksIGFuZCBQcmljZSBmcm9tIHRoZSBDYXJzOTMgZGF0YSBmcmFtZSkuIFRoZXJlLCB0aGUgYmFzaWMgZm9ybWF0IHdhcyBhIHNjYXR0ZXJwbG90IG9mIE1QRy5jaXR5IHZlcnN1cyBIb3JzZXBvd2VyLCB3aXRoIHBvaW50cyByZXByZXNlbnRlZCBhcyBidWJibGVzLCBzaXplZCBieSBQcmljZS4KCkhlcmUsIHlvdSBhcmUgYXNrZWQgdG8gY3JlYXRlIGEgdmFyaWF0aW9uIG9uIHRoaXMgcGxvdCwgdXNpbmcgdGhlIGZhY3RvciB2YXJpYWJsZSBDeWxpbmRlcnMgdG8gZGV0ZXJtaW5lIGJvdGggdGhlIHNpemUgYW5kIHRoZSBjb2xvciBvZiB0aGUgYnViYmxlcy4gVG8gZG8gdGhpcywgbm90ZSB0aGF0IGFzLm51bWVyaWMoQ2FyczkzJEN5bGluZGVycykgZ2VuZXJhdGVzIGEgc2VxdWVuY2Ugb2YgbnVtZXJpY2FsIHZhbHVlcyBmcm9tIDEgdG8gNiB0aGF0IHNwZWNpZnkgdGhlIHNpeCB1bmlxdWUgbGV2ZWxzIG9mIHRoZSBDeWxpbmRlcnMgZmFjdG9yLgoKVGhlIHBvaW50IG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gc2hvdyB0aGF0LCBpbiBjYXNlcyB3aGVyZSBjb2xvciBpcyBhbiBvcHRpb24sIHRoZSBjbGFyaXR5IG9mIHRoaXMgYnViYmxlcGxvdCBjYW4gYmUgaW1wcm92ZWQgc3Vic3RhbnRpYWxseSB0aHJvdWdoIHRoZSB1c2Ugb2YgY29sb3IgaW4gYWRkaXRpb24gdG8gc3ltYm9sIHNpemUuIFNpbmNlIHRoZSBDeWxpbmRlcnMgdmFyaWFibGUgZXhoaWJpdHMgc2l4IHVuaXF1ZSB2YWx1ZXMsIHNpeCBjb2xvcnMgYXJlIHJlcXVpcmVkIHRvIG1ha2UgdGhpcyBlbmhhbmNlbWVudCwgc28gdGhlIHRvcCBzaXggY29sb3JzIHJlY29tbWVuZGVkIGJ5IElsaWluc2t5IGFuZCBTdGVlbGUgYXJlIHVzZWQgaGVyZS4KCmBgYHtyfQojIElsaWluc2t5IGFuZCBTdGVlbGUgY29sb3IgbmFtZSB2ZWN0b3IKSVNjb2xvcnMgPC0gYygicmVkIiwgImdyZWVuIiwgInllbGxvdyIsICJibHVlIiwKICAgICAgICAgICAgICAiYmxhY2siLCAid2hpdGUiLCAicGluayIsICJjeWFuIiwKICAgICAgICAgICAgICAiZ3JheSIsICJvcmFuZ2UiLCAiYnJvd24iLCAicHVycGxlIikKIyBDcmVhdGUgdGhlIGBjeWxpbmRlckxldmVsYCB2YXJpYWJsZQpjeWxpbmRlckxldmVscyA8LSBhcy5udW1lcmljKENhcnM5MyRDeWxpbmRlcnMpCgoKIyBDcmVhdGUgdGhlIGNvbG9yZWQgYnViYmxlcGxvdApzeW1ib2xzKENhcnM5MyRIb3JzZXBvd2VyLCBDYXJzOTMkTVBHLmNpdHksIAogICAgICAgIGNpcmNsZXMgPSBjeWxpbmRlckxldmVscywgaW5jaGVzID0gMC4yLCAKICAgICAgICBiZyA9IElTY29sb3JzW2N5bGluZGVyTGV2ZWxzXSkKYGBgCgpVc2luZyBjb2xvciB0byBlbmhhbmNlIHN0YWNrZWQgYmFycGxvdHMKVGhlIG1vc3QgY29tbW9uIGJhcnBsb3QgY29uc2lzdHMgb2YgYSBjb2xsZWN0aW9uIG9mIHZlcnRpY2FsIGJhcnMsIGVhY2ggcmVwcmVzZW50aW5nIHNvbWUgY2hhcmFjdGVyaXN0aWMgb2Ygb25lIG9mIGEgZmluaXRlIG51bWJlciBvZiBkYXRhc2V0cyBvciBkYXRhIHN1YnNldHMuIFNldmVyYWwgcHJldmlvdXMgZXhlcmNpc2VzIGhhdmUgaWxsdXN0cmF0ZWQgdGhlIHV0aWxpdHkgb2YgdGhlIHNvbWV3aGF0IGxlc3MgY29tbW9uIGhvcml6b250YWwgYmFycGxvdCwgdXNlZnVsIGluIHBhcnQgYmVjYXVzZSBpdCBhbGxvd3MgdGV4dCB0byBiZSBkaXNwbGF5ZWQgaG9yaXpvbnRhbGx5IGFjcm9zcyB0aGUgYmFycywgYXMgaWxsdXN0cmF0ZWQgaW4gRXhlcmNpc2UgMS4KCkFub3RoZXIgdXNlZnVsIHZhcmlhbnQgb2YgdGhlIHN0YW5kYXJkIGJhciBwbG90IGlzIHRoZSBzdGFja2VkIGJhciBwbG90LCB3aGVyZSBlYWNoIGJhciBpbiB0aGUgcGxvdCBpcyBwYXJ0aXRpb25lZCBpbnRvIHNlZ21lbnRzIGNoYXJhY3Rlcml6aW5nIHBvcnRpb25zIG9mIHRoZSBkYXRhIGNoYXJhY3Rlcml6ZWQgYnkgdGhlIGJhci4gU3RhY2tlZCBiYXIgcGxvdHMgY2FuIGFsc28gYmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBiYXJwbG90KCkgZnVuY3Rpb24uIEhlcmUsIGVhY2ggYmFyIGlzIHNwZWNpZmllZCBieSBhIG1hdHJpeCB3aG9zZSBjb2x1bW5zIHNwZWNpZnkgdGhlIGhlaWdodHMgb2YgdGhlIHNlZ21lbnRzIGluIGVhY2ggYmFyLgoKQnkgZGVmYXVsdCwgdGhlIGJhcnBsb3QoKSBmdW5jdGlvbiBnZW5lcmF0ZXMgc3RhY2tlZCBiYXIgcGxvdHMgdXNpbmcgZGlmZmVyZW50IHNoYWRlcyBvZiBncmF5IGZvciB0aGUgZGlmZmVyZW50IHNlZ21lbnRzIG9mIGVhY2ggYmFyIGluIHRoZSBwbG90LiBUaGUgcG9pbnQgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBzaG93IHRoYXQsIGlmIHdlIGNhbiB1c2UgaXQsIGNvbG9yIGNhbiBiZSBhIG1vcmUgZWZmZWN0aXZlIGFsdGVybmF0aXZlLgoKYGBge3J9CiMgQ3JlYXRlIGEgdGFibGUgb2YgQ3lsaW5kZXJzIGJ5IE9yaWdpbgp0YmwgPC0gdGFibGUoQ2FyczkzJEN5bGluZGVycywgQ2FyczkzJE9yaWdpbikKCiMgQ3JlYXRlIHRoZSBkZWZhdWx0IHN0YWNrZWQgYmFycGxvdApiYXJwbG90KHRibCkKCiMgRW5oYW5jZSB0aGlzIHBsb3Qgd2l0aCBjb2xvcgpiYXJwbG90KHRibCwgY29sID0gSVNjb2xvcnMpCmBgYAoKVGhlIHRhYnBsb3QgcGFja2FnZSBhbmQgZ3JpZCBncmFwaGljcwpUaGUgdGFicGxvdCBwYWNrYWdlIGFsbG93cyB5b3UgdG8gdGFwIGludG8gdGhlIHBvd2VyIG9mIGdyaWQgZ3JhcGhpY3Mgd2l0aG91dCBleHBsaWNpdCBrbm93bGVkZ2Ugb2YgaG93IHRoZSBzeXN0ZW0gd29ya3MgdW5kZXIgdGhlIGhvb2QuIFRoZSBtYWluIGZ1bmN0aW9uIGluIHRhYnBsb3QgaXMgdGFibGVwbG90KCksIGRldmVsb3BlZCB0byB2aXN1YWxpemUgZGF0YSBkaXN0cmlidXRpb25zIGFuZCByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIGluIGxhcmdlIGRhdGFzZXRzLgoKU3BlY2lmaWNhbGx5LCB0aGUgdGFibGVwbG90KCkgZnVuY3Rpb24gY29uc3RydWN0cyBhIHNldCBvZiBzaWRlLWJ5LXNpZGUgaG9yaXpvbnRhbCBiYXJwbG90cywgb25lIGZvciBlYWNoIHZhcmlhYmxlLiBUaGlzIGZ1bmN0aW9uIHdvcmtzIGJlc3Qgd2hlbiB2aWV3aW5nIHVwIHRvIGFib3V0IDEwIHZhcmlhYmxlcyBhdCBhIHRpbWUsIGZvciBkYXRhc2V0cyB3aXRoIGFyYml0cmFyaWx5IG1hbnkgcmVjb3Jkcy4gSW4gdGhpcyBleGVyY2lzZSwgeW91IGFyZSBhc2tlZCB0byBhcHBseSB0aGlzIGZ1bmN0aW9uIHRvIGEgZGF0YXNldCB3aXRoIGp1c3QgdW5kZXIgNjgsMDAwIHJlY29yZHMgYW5kIDExIHZhcmlhYmxlcy4KClRoZSB0YWJsZXBsb3QoKSBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhIGRhdGEgZnJhbWUgYW5kLCBpZiBubyBvcHRpb25hbCBhcmd1bWVudHMgYXJlIHNwZWNpZmllZCwgaXQgc2VsZWN0cyB0aGUgZmlyc3QgZGF0YSBjb2x1bW4gYXMgdGhlIHJlZmVyZW5jZSB2YXJpYWJsZS4gVGhpcyB2YXJpYWJsZSBjYW4gYmUgb2YgYW55IHR5cGUsIGJ1dCB0aGUgZGlzcGxheSBpcyBlYXNpZXN0IHRvIGV4cGxhaW4gd2hlbiBpdCdzIG51bWVyaWMsIGFzIGluIHRoZSBleGFtcGxlIGNvbnNpZGVyZWQgaGVyZS4KCkZvciBmdXJ0aGVyIGRldGFpbHMsIHJlZmVyIHRvIHRoZSB2aWduZXR0ZSBWaXN1YWxpemF0aW9uIG9mIGxhcmdlIGRhdGFzZXRzIHdpdGggdGFicGxvdCB0aGF0IGFjY29tcGFuaWVzIHRoZSBoZWxwIGZpbGVzIGZvciB0aGUgdGFicGxvdCBwYWNrYWdlLgoKYGBge3J9CiMgTG9hZCB0aGUgaW5zdXJhbmNlRGF0YSBwYWNrYWdlCmxpYnJhcnkoaW5zdXJhbmNlRGF0YSkKCiMgVXNlIHRoZSBkYXRhKCkgZnVuY3Rpb24gdG8gbG9hZCB0aGUgZGF0YUNhciBkYXRhIGZyYW1lCmRhdGEoZGF0YUNhcikKCiMgTG9hZCB0aGUgdGFicGxvdCBwYWNrYWdlCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHRhYnBsb3QpKQoKIyBHZW5lcmF0ZSB0aGUgZGVmYXVsdCB0YWJsZXBsb3QoKSBkaXNwbGF5CnRhYmxlcGxvdChkYXRhQ2FyKQpgYGAKCkEgbGF0dGljZSBncmFwaGljcyBleGFtcGxlCkFub3RoZXIgcGFja2FnZSBidWlsdCBvbiBncmlkIGdyYXBoaWNzIGlzIGxhdHRpY2UsIGJ1dCB1bmxpa2UgdGFicGxvdCwgbGF0dGljZSBpcyBhIGdlbmVyYWwtcHVycG9zZSBncmFwaGljcyBwYWNrYWdlIHRoYXQgcHJvdmlkZXMgYWx0ZXJuYXRpdmUgaW1wbGVtZW50YXRpb25zIG9mIG1hbnkgb2YgdGhlIHBsb3R0aW5nIGZ1bmN0aW9ucyBhdmFpbGFibGUgaW4gYmFzZSBncmFwaGljcy4gU3BlY2lmaWMgZXhhbXBsZXMgaW5jbHVkZSBzY2F0dGVycGxvdHMgd2l0aCB0aGUgeHlwbG90KCkgZnVuY3Rpb24sIGJhciBjaGFydHMgd2l0aCB0aGUgYmFyY2hhcnQoKSBmdW5jdGlvbiwgYW5kIGJveHBsb3RzIHdpdGggdGhlIGJ3cGxvdCgpIGZ1bmN0aW9uLgoKT25lIGltcG9ydGFudCBkaWZmZXJlbmNlIGJldHdlZW4gbGF0dGljZSBncmFwaGljcyBhbmQgYmFzZSBncmFwaGljcyBpcyB0aGF0IHNpbWlsYXIgZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiBib3RoIGdyYXBoaWNzIHN5c3RlbXMgb2Z0ZW4gcHJvZHVjZSB2ZXJ5IGRpZmZlcmVudCByZXN1bHRzIHdoZW4gYXBwbGllZCB0byB0aGUgc2FtZSBkYXRhLiBBcyBhIHNwZWNpZmljIGV4YW1wbGUsIHRoZSBid3Bsb3QoKSBmdW5jdGlvbiBjcmVhdGVzIGhvcml6b250YWwgYm94cGxvdHMsIHdoaWxlIHRoZSBkZWZhdWx0IHJlc3VsdCBvZiB0aGUgYm94cGxvdCgpIGlzIGEgdmVydGljYWwgYm94cGxvdCBkaXNwbGF5LgoKQW5vdGhlciBtb3JlIGltcG9ydGFudCBkaWZmZXJlbmNlIGJldHdlZW4gbGF0dGljZSBhbmQgYmFzZSBncmFwaGljcyBpcyB0aGF0IGxhdHRpY2UgZ3JhcGhpY3Mgc3VwcG9ydHMgY29uZGl0aW9uYWwgcGxvdHMgdGhhdCBzaG93IHRoZSBzZXBhcmF0ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdmFyaWFibGVzIHdpdGhpbiBkaWZmZXJlbnQgZ3JvdXBzLiBUaGlzIGNhcGFiaWxpdHkgaXMgaWxsdXN0cmF0ZWQgaW4gdGhpcyBleGVyY2lzZSwgd2hlcmUgeW91IGFyZSBhc2tlZCB0byBjb25zdHJ1Y3QgYSBwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMgY2Fsb3JpZXMgYW5kIHN1Z2FycyBmcm9tIHRoZSBVU2NlcmVhbCBkYXRhIGZyYW1lLCBjb25kaXRpb25hbCBvbiB0aGUgdmFsdWUgb2YgdGhlIHNoZWxmIHZhcmlhYmxlLgoKYGBge3J9CiMgTG9hZCB0aGUgbGF0dGljZSBwYWNrYWdlCmxpYnJhcnkobGF0dGljZSkKCiMgVXNlIHh5cGxvdCgpIHRvIGNvbnN0cnVjdCB0aGUgY29uZGl0aW9uYWwgc2NhdHRlcnBsb3QKeHlwbG90KGNhbG9yaWVzIH4gc3VnYXJzIHwgYXMuZmFjdG9yKHNoZWxmKSwgZGF0YSA9IFVTY2VyZWFsKQpgYGAKCkEgZ2dwbG90MiBncmFwaGljcyBleGFtcGxlClRoaXMgZmluYWwgZXhlcmNpc2UgcHJvdmlkZXMgYW4gaW50cm9kdWN0aW9uIHRvIHRoZSBnZ3Bsb3QyIGdyYXBoaWNzIHBhY2thZ2UuIExpa2UgdGhlIGxhdHRpY2UgcGFja2FnZSwgdGhlIGdncGxvdDIgcGFja2FnZSBpcyBhbHNvIGJhc2VkIG9uIGdyaWQgZ3JhcGhpY3MgYW5kIGl0IGFsc28gcmVwcmVzZW50cyBhIGdlbmVyYWwgcHVycG9zZSBncmFwaGljcyBwYWNrYWdlLgoKVGhlIHVuaXF1ZSBmZWF0dXJlIG9mIHRoZSBnZ3Bsb3QyIHBhY2thZ2UgaXMgdGhhdCBpdCBpcyBiYXNlZCBvbiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcywgYSBzeXN0ZW1hdGljIGFwcHJvYWNoIHRvIGJ1aWxkaW5nIGFuZCBtb2RpZnlpbmcgZ3JhcGhpY2FsIGRpc3BsYXlzLCBzdGFydGluZyB3aXRoIGEgYmFzaWMgZ3JhcGhpY3MgZWxlbWVudCBhbmQgcmVmaW5pbmcgaXQgdGhyb3VnaCB0aGUgYWRkaXRpb24gb2Ygc3VjY2Vzc2l2ZSBtb2RpZmllcnMuCgpUaGlzIGV4ZXJjaXNlIHByb3ZpZGVzIGEgc2ltcGxlIGlsbHVzdHJhdGlvbiBvZiB0aGUgYXBwcm9hY2guIFNwZWNpZmljYWxseSwgeW91IGFyZSBhc2tlZCB0byB1c2UgZ2dwbG90MiB0bywgZmlyc3QsIGNyZWF0ZSBhIHNpbXBsZSBzY2F0dGVycGxvdCBvZiBNUEcuY2l0eSB2ZXJzdXMgSG9yc2Vwb3dlciBmcm9tIHRoZSBDYXJzOTMgZGF0YSBmcmFtZS4gTmV4dCwgeW91IGFyZSBhc2tlZCB0byBhZGQgYSBzaW1wbGUgbW9kaWZpZXIgdGhhdCBhZGRzIGNvbG9yIGJhc2VkIG9uIHRoZSB2YWx1ZSBvZiB0aGUgQ3lsaW5kZXJzIHZhcmlhYmxlLiBGaW5hbGx5LCB5b3UgYXJlIGFza2VkIHRvIGNvbnZlcnQgdGhpcyByZXN1bHQgaW50byBhIGNvbG9yZWQgYnViYmxlIHBsb3QsIHdpdGggYm90aCBidWJibGUgc2l6ZXMgYW5kIGNvbG9ycyBkZXRlcm1pbmVkIGJ5IHRoZSBDeWxpbmRlcnMgdmFyaWFibGUuCgpUaGUgcHJpbWFyeSBwdXJwb3NlIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZ2l2ZSB5b3UgYSBmbGF2b3Igb2YgdGhlIGdncGxvdDIgcGFja2FnZS4gRGF0YUNhbXAgb2ZmZXJzIHNldmVyYWwgY291cnNlcyBkZWRpY2F0ZWQgdG8gdXNpbmcgdGhpcyBwb3B1bGFyIGdyYXBoaWNzIHBhY2thZ2UgdG8gZ2VuZXJhdGUgaGlnaC1xdWFsaXR5IGRhdGEgdmlzdWFsaXphdGlvbnMuCgpgYGB7cn0KIyBMb2FkIHRoZSBnZ3Bsb3QyIHBhY2thZ2UKbGlicmFyeShnZ3Bsb3QyKQoKIyBDcmVhdGUgdGhlIGJhc2ljIHBsb3QgKG5vdCBkaXNwbGF5ZWQpOiBiYXNlUGxvdApiYXNlUGxvdCA8LSBnZ3Bsb3QoQ2FyczkzLCBhZXMoeCA9IEhvcnNlcG93ZXIsIHkgPSBNUEcuY2l0eSkpCgojIERpc3BsYXkgdGhlIGJhc2ljIHNjYXR0ZXJwbG90CmJhc2VQbG90ICsgCiAgZ2VvbV9wb2ludCgpCgojIENvbG9yIHRoZSBwb2ludHMgYnkgQ3lsaW5kZXJzIHZhbHVlCmJhc2VQbG90ICsgCiAgZ2VvbV9wb2ludChjb2xvdXIgPSBJU2NvbG9yc1tDYXJzOTMkQ3lsaW5kZXJzXSkKCiMgTWFrZSB0aGUgcG9pbnQgc2l6ZXMgYWxzbyB2YXJ5IHdpdGggQ3lsaW5kZXJzIHZhbHVlCmJhc2VQbG90ICsgCiAgZ2VvbV9wb2ludChjb2xvdXIgPSBJU2NvbG9yc1tDYXJzOTMkQ3lsaW5kZXJzXSwgCiAgICAgICAgICAgICBzaXplID0gYXMubnVtZXJpYyhDYXJzOTMkQ3lsaW5kZXJzKSkKYGBgCgo=